First time SQLite3 user python 3, syntax error in print - sqlite

I'm working on a program that is able to make quizzes by exporting questions into a database. I've looked on the internet for a bit and it said that one of the easiest ways to import or export to a database in python is to use the SQLite3 plugin, so I'm trying it out.This is the first time I've used the SQLite3 plugin with python, and I keep getting a syntax error on the self.connection.commit() in:
def AddQuestion(self, Question, Answer1, Answer2, Answer3, Answer4):
self.cursor.execute("""INSERT INTO questions
VALUES (?, ?, ?, ?, ?, ?)""", (None, Question, Answer1, Answer2, Answer3, Answer4, CorrectAnswer)
self.connection.commit()
If I were to turn it into a comment by adding # before it, it would tell me that the print in this was a syntax error:
print ("Would you like to make a test? Or would you like to take a test?")
Maybe its my indentation, or am I doing something wrong?
import squlite3
class QuestionStorage(object):
def _init_(self, path):
self.connection = sqlite3.connect(path)
self.cursor = self.connection.cursor ()
def Close(self):
self.cursor.close()
self.connection.close()
def CreateDb(self):
query = """CREATE TABLE questions
(id INTEGER PRIMARY KEY, Question TEXT, Answer1 TEXT, Answer2 TEXT, Answer3 TEXT, Answer4 TEXT, CorrectAnswer TEXT)"""
self.cursor.exeute(query)
self.connection.commit()
#self.cursor.close()
def AddQuestion(self, Question, Answer1, Answer2, Answer3, Answer4):
self.cursor.execute("""INSERT INTO questions
VALUES (?, ?, ?, ?, ?, ?)""", (None, Question, Answer1, Answer2, Answer3, Answer4, CorrectAnswer)
self.connection.commit()
def GetQuestion(self, index = None):
self.cursor.execute("""SELECT * FROM questions WEHRE id=?""", (index,))
print ("Would you like to make a test? Or would you like to take a test?")
testTaker = input ("To create a test, type Create. To take a test, type Take.")
if testTaker == "Create":
testName = input ("Give your test a name.")
testQ = int(input ("How many questions will be on this test? (Numeric value only.)"))
testType = input ("Will this test be multiple choice? (y/n)")
if testType == "N" or "n":
counter = 1
qs = QuestionStorage("questions.db")
qs.CreateDb()
counter = 1
while counter >= testQ:
Answer = []
Question = input ("What is your question?")
Answer[1] = input ("What is the first answer?")
Answer[2] = input ("What is the second answer?")
Answer[3] = input ("What is the third answer?")
Answer[4] = input ("What is your last answer?")
correctAnswer = input("Which answer is the correct answer? (1, 2, 3, or 4?)")
Answer[5] = Answer[correctAnswer]
qs.AddQuestion(Question, Answer[1] , Answer[2], Answer[3], Answer[4], Answer[5])
counter +=1
else:
and then after the else, I'd have the code for reading the database to take a test.
If anyone can help me out with this, that would be great. Right now I'm just trying to get it to the point where I can run it in debug.

You forgot to close the parentheses here:
self.cursor.execute("""INSERT INTO questions
VALUES (?, ?, ?, ?, ?, ?)""", (None, Question, Answer1, Answer2, Answer3, Answer4, CorrectAnswer)
Put another closing ) at the end of the line.

Related

Julia dataframe to database ODBC , not slow solution

I want to insert a Dataframe in a table using ODBC.jl , the table already exists and it seems that i can't use the function ODBC.load with it (even with the append=true).
usually i insert DataFrames with copyIn by loading the dataframe as a csv but with just ODBC it seems i can't do that .
The last thing i found is :
stmt = ODBC.prepare(dsn, "INSERT INTO cool_table VALUES(?, ?, ?)")
for row = 1:size(df, 1)
ODBC.execute!(stmt, [df[row, x] for x = 1:size(df, 2)])
end
but this is line by line , it's incredibly long to insert everything .
I tried also to do it myself like this :
_prepare_field(x::Any) = x
_prepare_field(x::Missing) = ""
_prepare_field(x::AbstractString) = string(''', x, ''')
row_names = join(string.(Tables.columnnames(table)), ",")
row_strings = imap(Tables.eachrow(table)) do row
join((_prepare_field(x) for x in row), ",") * "\n"
end
query = "INSERT INTO $tableName($row_names) VALUES $row_strings"
#debug "Inserting $(nrow(df)) in $tableName)"
DBInterface.execute(db.conn, query)
but it throw me an error because of some "," not at the right place at like col 9232123
which i can't find because i have too many lines , i guess it's the _prepare_field that doesn't cover all possible strings escape but i can't find another way .
Did i miss something and there is a easier way to do it ?
Thank you

Snowflake ODBC and VARIANT data type

Using odbctest and Snowflake 64-bit ODBC driver for Windows:
Created a table in snowflake using this DDL:
CREATE TABLE "SFDEST"."QAUSER"."BT14726"
("VARCHAR_10_COL" VARCHAR (10),
"VARCHAR_4000_COL" VARCHAR (4000) ,
"CHAR_10_COL" CHAR (10) ,
"CLOB_COL" VARIANT,
"ROWID" CHAR (18) NOT NULL )
Then attempted to prepare an insert statement:
SQL attempted:
INSERT INTO "SFDEST"."QAUSER"."BT14726"
("VARCHAR_10_COL",
"VARCHAR_4000_COL",
"CHAR_10_COL",
"ROWID",
"CLOB_COL")
VALUES ( ?, ?, ?, ?, ?)
But this error was returned:
Prepare of destination insert statement failed. SQL compilation error:
Expression type does not match column data type, expecting VARIANT but
got VARCHAR(1) for column CLOB_COL
This is the relevant portion of odbc trace:
sqdrsvc 3dfc-52bc ENTER SQLPrepare
HSTMT 0x000000435C961620
UCHAR * 0x000000435D262720 [ 140] "INSERT INTO "SFDEST"."QAUSER"."BT14726" ("VARCHAR_10_COL",
"VARCHAR_4000_COL", "CHAR_10_COL", "ROWID", "CLOB_COL") VALUES ( ?,
?, ?, ?, ?) "
SDWORD 140
sqdrsvc 3dfc-52bc EXIT SQLPrepare with return code
-1 (SQL_ERROR)
HSTMT 0x000000435C961620
UCHAR * 0x000000435D262720 [ 140] "INSERT INTO "SFDEST"."QAUSER"."BT14726" ("VARCHAR_10_COL",
"VARCHAR_4000_COL", "CHAR_10_COL", "ROWID", "CLOB_COL") VALUES ( ?,
?, ?, ?, ?) "
SDWORD 140
DIAG [22000] SQL compilation error: Expression type does not match column data type, expecting VARIANT but got
VARCHAR(1) for column CLOB_COL (2023)
If you have a string that is formatted as a valid JSON blob, you need to use PARSE_JSON to convert it into an actual variant type so that SnowFlake can recognize it as such.
Probably something like this:
INSERT INTO "SFDEST"."QAUSER"."BT14726"
("VARCHAR_10_COL",
"VARCHAR_4000_COL",
"CHAR_10_COL",
"ROWID",
"CLOB_COL")
VALUES ( ?, ?, ?, ?, PARSE_JSON(?))

Using sqlite how can i update or insert to a table using a condition?

Having a blank table with three columns
CREATE TABLE AssyData ( AID int NOT NULL PRIMARY KEY UNIQUE , MaxDef float , MaxDefLC int , MaxDefNID int , Comps text , SubAssys text )
I would like to Update or insert new values if the new MaxMag is larger than the current one and if the AID is the same. AID is a unique Primary key. Assuming an AID of 100 I have tried the following, but with no success:
INSERT INTO AssyData
(AID , MaxDef , MaxDefLC , MaxDefNID , Comps , SubAssys)
VALUES( 100 , 101 , 202 , 203 , "" , "")
ON CONFLICT(AID)
DO UPDATE
SET
MaxDef = excluded.MaxDef ,
MaxDefNID = excluded.MaxDefNID ,
MaxDefLC = excluded.MaxDefLC ,
Comps = excluded.Comps ,
SubAssys = excluded.SubAssys
WHERE excluded.MaxDef > 100
I get the error "near "ON": syntax error"
What is wrong with my statement?
Thanks Shawn for the Approach.
In case your vesrsion of SQLite does not allow the use of UPSERT you can achieve what you need in 2 steps:
INSERT OR IGNORE INTO AssyData
(AID, MaxDef, MaxDefLC, MaxDefNID, Comps, SubAssys)
VALUES(100, 111, 202, 203, '', '');
This INSERT OR IGNORE will fail without an error if you try to insert a row with an AID that already exists in the table.
Then:
UPDATE AssyData
SET
MaxDef = 111,
MaxDefLC = 202,
MaxDefNID = 203,
Comps = '',
SubAssys = ''
WHERE AID = 100 AND MaxDef < 111;
This will fail if the row to be updated contains MaxDef equal or greater than the value 111.
See the demo.
In general such code needs special care when implemented, because as you can see the value of MaxDef (111 in this example) must be set 3 times.
Assuming you're using a somewhat recent (3.24 or newer) version of sqlite, you can use what's known as UPSERT:
INSERT INTO AssyData(AID, MaxMag, MaxDefNID) VALUES (?, ?, ?)
ON CONFLICT(AID) DO UPDATE SET MaxMag = excluded.MaxMag
, MaxDefNID = excluded.MaxDefNID
WHERE excluded.MaxMag > MaxMag;

Repeat a command while true or x times (equivalent of while/for loop)

I would like to repeat this command as many times as there is still sometextin the field note (several rows from the table itemNotes could have one or more sometext in the field note):
UPDATE itemNotes
SET
note = SUBSTR(note, 0, INSTR(LOWER(note), 'sometext')) || 'abc' || SUBSTR(note, INSTR(LOWER(note), 'sometext')+sometext_len)
WHERE
INSTR(LOWER(note), 'sometext') >= 0;
So a proto-code would be :
While (SELECT * FROM itemNotes WHERE note like "%sometext%") >1
UPDATE itemNotes
SET
note = SUBSTR(note, 0, INSTR(LOWER(note), 'sometext')) || 'abc' || SUBSTR(note, INSTR(LOWER(note), 'sometext')+sometext_len)
WHERE
INSTR(LOWER(note), 'sometext') >= 0;
END
But apparently Sqlite3 doesn't support While loop or for loop. They can be emulated with something like this but I have difficulties integrating what I want with this query:
WITH b(x,y) AS
(
SELECT 1,2
UNION ALL
SELECT x+ 1, y + 1
FROM b
WHERE x < 20
) SELECT * FROM b;
Any idea how to do this?
PS: I don't use replace because I want to replace all the case combinations of sometext (e.g. sometext, SOMEtext, SOmeText...) cf this question
Current input and desired output:
For a single row, a note field could look like (and many rows in the table itemNotescould look like this one):
There is SOmetext and also somETExt and more SOMETEXT and even more sometext
The query should output:
There is abc and also abc and more abc and even more abc
I am doing it on the zotero.sqlite, which is created by this file (line 85). The table is created by this query
CREATE TABLE itemNotes (
itemID INTEGER PRIMARY KEY,
parentItemID INT,
note TEXT,
title TEXT,
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE,
FOREIGN KEY (parentItemID) REFERENCES items(itemID) ON DELETE CASCADE
);
You just have your answer in your query:
UPDATE itemNotes
SET
note = SUBSTR(note, 0, INSTR(LOWER(note), 'sometext')) || 'abc' || SUBSTR(note, INSTR(LOWER(note), 'sometext')+sometext_len)
WHERE
note LIKE "%sometext%";
It will update all rows that contain sometext in the note field
UPDATE
If you want to update the field which has multiple occurrences in different cases and maintain the rest of the text the simplest solution imo is to use regex and for that you need an extension
UPDATE itemNotes
SET
note = regex_replace('\bsometext\b',note,'abc')
WHERE
note LIKE "%sometext%";
As recommended by Stephan in his last comment, I used python to do this.
Here is my code :
import sqlite3
import re
keyword = "sometext"
replacement = "abc"
db = sqlite3.connect(path_to_sqlite)
cursor = db.cursor()
cursor.execute(f'SELECT * FROM itemNotes WHERE note like "%{keyword}%"')
for row in cursor.fetchall():
row_regex = re.compile(re.escape(keyword), re.IGNORECASE)
row_regex_replaced = row_regex.sub(replacement, row[2])
rowID = row[0]
sql = "REPLACE INTO itemNotes (itemID,note) VALUES (?,?)"
data = (rowID, row_regex_replaced)
cursor.execute(sql, data)
db.commit()

Using R with RODBCext and RODBC to execute a SQL stored procedure

I am using the RODBCext package and the RODBC package to execute a stored procedure in SQL server 2008 using R. If I use this code the stored procedure works.
query <- "EXEC [dbo].[usp_SchoolMerge] #Number = ?,
#Name = ?,
#Type = ?,
#Comments = ?,
#DualEnrollment =?,
#CEP = ?,
#DistrictGuidId = ?,
#ImportName = ?,
#ImportID = ?"
query <- gsub("[[:space:]]+", " ", query)
con2 <- odbcConnect("database", uid="userid", pwd="password")
for(i in 1:nrow(us11_12_00_school)) {
sqlExecute(con2, query, us11_12_00_school[i,])
}
odbcClose(con2)
If I try to use the vectorized form explained here under 2.3.2 Using parameterized queries.
query <- "EXEC [dbo].[usp_SchoolMerge] #Number = ?,
#Name = ?,
#Type = ?,
#Comments = ?,
#DualEnrollment =?,
#CEP = ?,
#DistrictGuidId = ?,
#ImportName = ?,
#ImportID = ?"
query <- gsub("[[:space:]]+", " ", query)
con2 <- odbcConnect("database", uid="userid", pwd="password")
sqlExecute(con2, query, us11_12_00_school)
odbcClose(con2)
I get this error in R.
Error in sqlExecute(con2, query, us11_12_00_school) :
24000 0 [Microsoft][ODBC SQL Server Driver]Invalid cursor state
[RODBCext] Error: SQLExecute failed
If I use a data frame with only one row the vectorized code works. Anyone else had this problem? Any ideas?
Seems like you want to use only the first column of the us11_12_00_school - which you pass in the loop-version of the function with us11_12_00_school[i,]. In the vectorised version though, you pass in the whole dataframe!
I havent tested it out, but i guess passing the dataframe as us11_12_00_school[1,] in the vectorised version would give you the expected results?
I use the code below, and seems to work well. Hopefully it helps you too.
require(RODBC)
require(RODBCext)
ExecuteQuery <- function(query, arguments){
dbhandle <- odbcDriverConnect('driver={SQL Server Native Client 11.0};server=SereverName;database=DbName;trusted_connection=yes')
if(missing(arguments))
result <- sqlExecute(dbhandle, query = query, fetch = TRUE)
else
result <- sqlExecute(dbhandle, query =query, data=arguments, TRUE)
close(dbhandle)
return(result)
}
CallProcWithSomeParams <- function(param1, param2){
ExecuteQuery('exec dbo.procName ?, ?', data.frame(param1, param2))
}

Resources