Print values from another table SQLite3 w/ Python - python

I want to create a simple recipe script. So I have a Table with some recipes and one with ingredients. Now I linked all ingredients_id to the the recipe.
Is it possible to print the name of those id's from another table?
import sqlite3
conn = sqlite3.connect('food.db')
c = conn.cursor()
c.execute("""CREATE TABLE IF NOT EXISTS ingredients (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL)""")
c.execute("""CREATE TABLE IF NOT EXISTS recipes (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
quantity REAL,
ingredients_id TEXT,
FOREIGN KEY(ingredients_id) REFERENCES ingredients(id)
)""")
c.execute("INSERT INTO recipes VALUES ('0', 'Pasta with Tomato', '1', '2,3')")
c.execute("INSERT INTO ingredients VALUES ('2', 'Pasta')")
c.execute("INSERT INTO ingredients VALUES ('3', 'Tomato')")
c.execute("SELECT * FROM recipes WHERE id='0'")
print(c.fetchone())
conn.commit()
conn.close()

Your problem is classic many-to-many relationship.
Each product can be ingredient in many recipes, each recipe can have multiple ingredients.
To implement this, you need 3rd table, that holds "membership" per product per recipe. This is common (if not best) practice for m2m problem.
There's a lot of examples in SO, pls look for them

Related

How make list of ingredients in recipes in SQLITE3 Python

I'm trying make database of recipes. In the table "recipes" with col "ingredients", I would like to have a list of ingredient IDs, e.g. [2,5,7]. Can I make something like this or I should be looking for another solution?
import sqlite3
conn = sqlite3.connect('recipes.db')
c = conn.cursor()
c.execute('''CREATE TABLE recipes(ID INT, name TEXT, ingredients INT)''')
c.execute('''CREATE TABLE ingredients(ID INT, nazwa TEXT, kcal REAL)''')
Another idea is to make another table (The list of ingredients) where I will have 15 cols with number of ingredients.
c.execute('''CREATE TABLE The_list_of_ingredients(ID INT, ingredient1 INT, ingredient2 INT, ...)''')
Can I connect every ingredient 1, ingredient 2 ... with their respective ingredients ID?
You're likely looking for a many-to-many relation between recipes and their ingredients.
CREATE TABLE recipes(ID INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE ingredients(ID INTEGER PRIMARY KEY, name TEXT, kcal REAL);
CREATE TABLE recipe_ingredients(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
recipe_id INTEGER,
ingredient_id INTEGER,
quantity REAL,
FOREIGN KEY(recipe_id) REFERENCES recipes(ID),
FOREIGN KEY(ingredient_id) REFERENCES ingredients(ID)
);
This way your data might look something like e.g.
ingredients
id
name
kcal
1
egg
155
2
cream
196
recipes
id
name
1000
omelette
recipe_ingredients
recipe_id
ingredient_id
quantity
1000
1
100
1000
2
50
(assuming kcal is kcal per 100g, and quantity is in grams and a rather creamy omelette)
You can try to store id's as string
json.dumps(list_of_ingredients_ids)
But probably best solution is many to many relation

Ignore duplicate rows in PostgreSQL

I'm using python and psycopg2 to insert a dict to my PostgreSQL database.
I have postgres version 13.2
At the moment I only have the code below to execute :
INSERT INTO movie_data(title, description, rating, published, cast_and_crew, age_group, country)
VALUES ('movie name', 'something', 8, 2020, 'an actor', 'pg-13', 'GB')
But because I already have this row in my db I get the 'already exists' error.
I've tried the ON CONFLICT DO NOTHING but I get the error below :
there is no unique or exclusion constraint matching the ON CONFLICT specification
What's the best way to ignore the duplicate rows and keep on inserting?
I'm new to SQL so if anyone could explain and include the whole code for this purpose I would really appreciate it.
UPDATE : below is my CREATE TABLE statement
CREATE TABLE public.movie_data
(
title text COLLATE pg_catalog."default" NOT NULL,
description text COLLATE pg_catalog."default" NOT NULL,
published integer,
cast_and_crew text COLLATE pg_catalog."default",
age_group text COLLATE pg_catalog."default",
country text COLLATE pg_catalog."default",
rating integer,
CONSTRAINT movie_data_pkey PRIMARY KEY (title, description)
)
TABLESPACE pg_default;
ALTER TABLE public.movie_data
OWNER to postgres;
error is clear , you need to have a unique constraint on your table for the columns that needs to be unique
alter table movie_data
add constraint constraintname unique (title, description);
now you can use this constraint :
INSERT INTO movie_data(title, description, rating, published, cast_and_crew, age_group, country)
VALUES ('movie name', 'something', 8, 2020, 'an actor', 'pg-13', 'GB')
on conflict on constraint constraintname do nothing;
as Adrian pointed out , instead of that , if your Primary key is on those column that needs to be unique , you simply could :
INSERT INTO movie_data(title, description, rating, published, cast_and_crew, age_group, country)
VALUES ('movie name', 'something', 8, 2020, 'an actor', 'pg-13', 'GB')
on conflict (title, description) do nothing;
Why would you like to have a primary key with duplicated rows? The main purpose of primary keys is to uniqueliy identify rows.
I think you should drop your primary key:
alter table public.movie_data drop constraint movie_data_pkey;

How to add more than one information to the same ID?

I am creating a code that works with database, and would like to know how to add more than one information to the same ID.
It is for a student's note control code.
def add_series(self):
conn = sqlite3.connect('obje_bd.db')
cursor = conn.cursor()
id_ = self.ids.txt_id.text.encode('utf-8')
series = self.ids.txt_series_professor.text.encode('utf-8')
# alterando os dados da tabela
cursor.execute("""
# would like to put all series in the same ID.
INSERT INTO lista_professores WHERE id = ?, series = ?""")
conn.commit()
conn.close()
Typically you wouldn't directly, that is if the "more information" is a variable amount of information per id.
For example assume that a Student (the assumption is that a student's row has an id) has x number of notes.
You would not have x columns (as you would forever be adding new columns).
It would prove clumsy to place all the notes into single column with a separator e.g something like 'Hello this is my first note','Thankyou this is my second note' and so on.
e.g. if a comma separates data how do you cope with commas in the notes.
how do you split the data, say to find note 3?
What you would typically do is normalise the data and have a table for the notes, each note being an individual row. There would be a column in the notes table that relates the note to the respective student.
- SQLite is a relational database and handles relationships pretty well.
Example
Consider the following, where instead of a Student having x number of data (notes) in the Student table another table for the notes exists and each note contains a column for relating the note to the student :-
DROP TABLE IF EXISTS Student;
DROP TABLE IF EXISTS Note;
CREATE TABLE IF NOT EXISTS Student (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE IF NOT EXISTS Note(id INTEGER PRIMARY KEY, studentReference INTEGER, note TEXT);
INSERT INTO Student (name) VALUES ('Fred'),('Mary'),('Anne'); -- ids will be 1 2 and 3
INSERT INTO Note (studentReference,note) VALUES
(1,'My Note 1'),
(3,'My Note 1'),
(3,'My Note 2'),
(2,'My Note 1'),
(3,'My Note 3'),
(2,'My Note 2'),
(2,'My Note 3'),
(1,'My Note 2'),
(1,'My Note 3'),
(1,'My Note 4'),
(1,'My Note 5'),
(3,'My Note 4');
SELECT * FROM Student; -- The Student table
SELECT * FROM Note; -- The Note table
-- Get the Notes with the Student (both have the same result)
SELECT name, note FROM Note JOIN Student ON Student.id = Note.studentReference ORDER BY Student.name;
SELECT name, note FROM Student JOIN Note ON Student.id = Note.studentReference ORDER BY Student.name;
-- Get the number of notes and all the notes concatenated as a CSV per student
SELECT student.name,count(), group_concat(note) FROM student JOIN Note ON Student.id = Note.studentReference GROUP BY student.id;
Results
1 The Student Table
2 The Notes Table
3 and 4 Student and Notes
5 Number of notes and the notes as a CSV per student

SQLite with Python "Table has X columns but Y were supplied"

I have a python script that executes some simple SQL.
c.execute("CREATE TABLE IF NOT EXISTS simpletable (id integer PRIMARY KEY, post_body text, post_id text, comment_id text, url text);")
command = "INSERT OR IGNORE INTO simpletable VALUES ('%s', '%s', '%s', '%s')" % (comments[-1].post_body, comments[-1].post_id, comments[-1].comment_id,
comments[-1].url)
c.execute(command)
c.commit()
But when I execute it, I get an error
sqlite3.OperationalError: table simpletable has 5 columns but 4 values were supplied
Why is it not automatically filling in the id key?
In Python 3.6 I did as shown below and data was inserted successfully.
I used None for autoincrementing ID since Null was not found.
conn.execute("INSERT INTO CAMPAIGNS VALUES (?, ?, ?, ?)", (None, campaign_name, campaign_username, campaign_password))
The ID structure is as follows.
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
If you don't specify the target columns VALUES is expected to provide values for all columns and that you didn't do.
INSERT
OR IGNORE INTO simpletable
(text,
post_id,
comment_id,
text)
VALUES ('%s',
'%s',
'%s',
'%s');
Specifying the target columns is advisable in any case. The query won't break, if, for any reason, the order of the columns in the tables changes.
try to specify the columns names to ensure that the destination of values doesn't depends on order.
ex:
INTO simpletable
(text,
post_id,
comment_id,
text)
And if you wants the id column to be automatically incremented make sure to add Identity property on, or similar auto increment of your dbms.
ex:
CREATE TABLE IF NOT EXISTS simpletable (id integer PRIMARY KEY Identity(1,1),
and remember your script is not prepared to alter the table structure, only creation.
If you wrote code correctly delete your SQL file(name.db) and run your code again some time it solve the problem.
Imagine this is your code:
cursor.execute('''CREATE TABLE IF NOT EXISTS food(name TEXT , price TEXT)''')
cursor.execute('INSERT INTO food VALUES ("burger" , "20")')
connection.commit()
and you see an error like this:
table has 1 column but 2 values were supplied
it happened because for example you create a file with one column and then you modify your file to two column but you don't change the file name so compiler do not over write it because it exist.

Python sqlite - insert if not exists [duplicate]

I have an SQLite database. I am trying to insert values (users_id, lessoninfo_id) in table bookmarks, only if both do not exist before in a row.
INSERT INTO bookmarks(users_id,lessoninfo_id)
VALUES(
(SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
(SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+")
WHERE NOT EXISTS (
SELECT users_id,lessoninfo_id from bookmarks
WHERE users_id=(SELECT _id FROM Users
WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
SELECT _id FROM lessoninfo
WHERE Lesson="+lesson_no+")))
This gives an error saying:
db error near where syntax.
If you never want to have duplicates, you should declare this as a table constraint:
CREATE TABLE bookmarks(
users_id INTEGER,
lessoninfo_id INTEGER,
UNIQUE(users_id, lessoninfo_id)
);
(A primary key over both columns would have the same effect.)
It is then possible to tell the database that you want to silently ignore records that would violate such a constraint:
INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)
If you have a table called memos that has two columns id and text you should be able to do like this:
INSERT INTO memos(id,text)
SELECT 5, 'text to insert'
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');
If a record already contains a row where text is equal to 'text to insert' and id is equal to 5, then the insert operation will be ignored.
I don't know if this will work for your particular query, but perhaps it give you a hint on how to proceed.
I would advice that you instead design your table so that no duplicates are allowed as explained in #CLs answer below.
For a unique column, use this:
INSERT OR REPLACE INTO tableName (...) values(...);
For more information, see: sqlite.org/lang_insert
insert into bookmarks (users_id, lessoninfo_id)
select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;
This is the fastest way.
For some other SQL engines, you can use a Dummy table containing 1 record.
e.g:
select 1, 167 from ONE_RECORD_DUMMY_TABLE

Categories