Loading...
supersane avatar supersane 234 Точки

[Python] Databases

Здравейте, вчерашната лекция свързана с бази данни в питон ми беше много интересна, както и в някой аспекти сложна, защото до момента все още не съм имал допир до бази данни. Понеже докато лектора обясняваше за foreign ключа между двете таблици, аз бях вглъбен да направя втората задача и изпуснах някои части от обясненията. Това, което разбрах, е че в таблицата "sale", където реално са продажбите ние трябва да направим колона "catalog_id", която ще се свърза с другата таблица "catalog" или по-конректно с нейната колонка "id", която е primary key и съдържа уникални INTEGER стойности. Следователно, когато импортирам данни в таблицата "sale" аз трябва да правя заявка към таблицата "catalog" като от нея да взимам id-то на артикула със съвпадащ item_key, и после това id да го импортвам в таблицата "sale" в колоната catalog_id. И всъщност това е връзката между двете таблици. Предполагам не го обясних много добре затова поставям кода на двете импортиращи функции, ако може някой по-запознат да ги прегледа и каже дали има пропуски някъде.

# IMPORTING THE CATALOG INTO DB

def import_catalog_into_db(catalog_by_item_id, connection):
    cursor = connection.cursor()
    for catalog_entry in catalog_by_item_id.values():
        cursor.execute(
            "insert into catalog (item_key, category) values (?, ?)",
            [catalog_entry.item_id, catalog_entry.category_name]
        )
#IMPORTING THE SALES INTO DB

def import_sales_into_db(sales, connection):
    cursor = connection.cursor()
    for sale in sales:
        cursor.execute('SELECT id FROM CATALOG where item_key = ?', [sale.item_id])
        result = cursor.fetchone()
        cursor.execute("""
        insert or replace into sale (catalog_id, country, city_name, sale_timestamp, price) values (?, ?, ?, ?, ?)
        """, [result[0], sale.country, sale.city, sale.sale_timestamp, float(sale.price)])

 

След пускане на програмата и когато заредя базата данни през sqlitestudio, ми изглежда сякаш всичко е наред. Но за да тръгне програмата трябва предварително да съм изтрил базата данни, иначе ми дава следния ексепшън: 

  File "/home/supersane/Development/softuni/Python/databases/sqlite_import.py", line 58, in import_catalog_into_db
    [catalog_entry.item_id, catalog_entry.category_name]
sqlite3.IntegrityError: UNIQUE constraint failed: catalog.item_key

Това, което предполагам, е че във функцията, където импортирам каталога, insert, трябва да го заменя също с insert or replace, но честно казано не съм сигурен дали това е правилния метод и дали от един проблем няма да си създам още няколко. Ще се радвам на някакво съдействие от ваша страна, благодаря.

Тагове:
0
Python
RoYaL avatar RoYaL Trainer 6849 Точки

Възможно е във файла sales да има продажби, чиито артикули ги няма във файла каталог. Т.е. все едно си продал нещо, което не съществува.

Та правилно си разбрал връзката - продажбата има релация (външен ключ) към артикулите. Т.е. всяка продажба си има по един артикул, ако трябва да го гледаме в обектно ориентирания свят.

Когато се опитваш да импортнеш продажба е важно да се подсигуриш, че такъв артикул има. Ако имаш продажба с item_key = "fgfdgh", но такъв няма в таблицата catalog, то резултата от селекта, който правиш преди инсърта няма да върне стойности и съответно не трябва да импортваш тази продажба.

Направи проверка дали в result се е появило нещо или е останал None. Може да проверяваш и с cursor.rowcount > 0

А самата грешка, която ти изписва е защото вече такъв артикул с такъв item_key, тъй като в DDL-а си написал UNIQUE за тази колона. Когато се опиташ да добавиш артикул със същия ключ, базата гърми. Имаш две възможности - да провериш дали такъв артикул вече има със SELECT и да не добавяш нов, или да кажеш INSERT OR REPLACE, което евентуално ще промени данните за записа с този item_key (т.е. няма да пипа item_key-а, но ако например категорията при втория импорт е различна, ще я актуализира)

 

 

0
03/02/2016 14:07:53
supersane avatar supersane 234 Точки

Благодаря за изчерпателния отговор @RoYaL, в метода за импортиране сложих също insert or replace и сега работи без ексепшъна. За проверката, която ми каза не се бях сетил. Сега ми идва въпроса, ако result е празен, какво е редно да направим? Да пропуснем нищо да импортваме или да сложим някаква стойност, като индикация, че нещо не е наред? Как би било по-добре?

0
RoYaL avatar RoYaL Trainer 6849 Точки

Със сигурност не е добра идея да слагаш нещо в базата. Или поне не в тази таблица. Може да индикираш на стандартния аутпут, че нещо не е наред. Спомняш ли си от първите лекции - логера? Другият вариант е да направиш таблица за логване на различни събития (обикновено се прави в друга база данни), където да отбележиш, че поради някаква причина има продажба на несъществуващ артикул, така че примерно в края на отчетния период да се види кой е този продавач, дето успява да продава нещо, дето го нямате във вашата мрежа, например :))

1
supersane avatar supersane 234 Точки

Благодаря за предложението, това с допълнителната база данни ми допада доста, но май май ме домързя да го реализирам затова добавих следното:

        if result is None:
            with open('res/errors.txt', 'a') as f:
                f.write('{}: Unable to import {} because of invalid item id.\n'.format(datetime.utcnow(), str(sale)))
                logging.error('{}: Unable to import {} because of invalid item id.\n'.format(datetime.utcnow(), str(sale)))
        else:
            cursor.execute("""
            insert or replace into sale (catalog_id, country, city_name, sale_timestamp, price) values (?, ?, ?, ?, ?)
            """, [result[0], sale.country, sale.city, sale.sale_timestamp, float(sale.price)])

 

0
03/02/2016 23:17:23
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.