How to use executemany in pyodbc to run multiple SELECT queries - pyodbc

Im using PYODBC to query an SQL DB multiple times based on the values of a pandas dataframe column (seen below as a list of values, since I used the ToList() function to turn the column into a list.
#the connection string
cnxn = pyodbc.connect(driver='{SQL Server}', server = 'NameOfTheServer',autocommit = True,uid ='name',pwd ='password')
cursor = cnxn.cursor()
params = ['3122145', '523532236']
sql = ("""
SELECT SO.column
FROM table AS SO
WHERE SO.column = ?
""")
cursor.executemany(sql, params)
row = cursor.fetchone()
the executemany function throws an error even though I'm using a list:
TypeError: ('Params must be in a list, tuple, or Row', 'HY000')

.executemany is not intended to be used with SELECT statements. If we try, we only get the last row back:
cnxn = pyodbc.connect(connection_string, autocommit=True)
crsr = cnxn.cursor()
crsr.execute("CREATE TABLE #tmp (id int primary key, txt varchar(10))")
crsr.execute(
"INSERT INTO #tmp (id,txt) "
"VALUES (1,'one'),(2,'two'),(3,'three'),(4,'four'),(5,'five')"
)
print(crsr.execute("SELECT * FROM #tmp").fetchall())
"""console output:
[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five')]
"""
sql = "SELECT * FROM #tmp WHERE id = ?"
list_of_tuples = [(1,), (3,), (5,)]
crsr.executemany(sql, list_of_tuples)
print(crsr.fetchall())
"""console output:
[(5, 'five')]
"""
try:
crsr.nextset()
print(crsr.fetchall())
except pyodbc.ProgrammingError as pe:
print(pe)
"""console output:
No results. Previous SQL was not a query.
"""
Instead, we need to build a string of parameter placeholders and use it in an IN clause, like this:
tuple_of_scalars = tuple(x[0] for x in list_of_tuples)
sql = f"SELECT * FROM #tmp WHERE id IN ({','.join('?' * len(tuple_of_scalars))})"
print(sql)
"""console output:
SELECT * FROM #tmp WHERE id IN (?,?,?)
"""
crsr.execute(sql, tuple_of_scalars)
print(crsr.fetchall())
"""console output:
[(1, 'one'), (3, 'three'), (5, 'five')]
"""

Related

can I search two sqlite fts5 index's across two tables?

I have a tasks application with two tables. One table has the task name, date, owner etc and the other has the comments for the task linked to the task number so there can be multiple comments attached to a single task.
Both tables have FTS5 indexes. Within my app I want to search both tables for a word and present the rows to the user. I have the below working for each table individually but how do I construct a query that returns data from both FTS5 tables?
(python3.6)
c.execute("select * from task_list where task_list = ? ", [new_search])
c.execute("select * from comments where comments = ? ", [new_search])
thanks #tomalak never thought of doing that, was focused on the query. Here's what I came up with and works for my purposes. Probably better ways to achieve the same result but I'm a beginner. This is a Tkinter app.
def db_search():
rows = ''
conn = sqlite3.connect('task_list_database.db')
c = conn.cursor()
d = conn.cursor()
new_search = entry7.get()
c.execute("select * from task_list where task_list = ? ", [new_search])
d.execute("select * from comments where comments = ? ", [new_search])
rows1 = c.fetchall()
rows2 = d.fetchall()
rows = rows1 + rows2
clear_tree(tree)
for row in rows:
tree.insert("", END, values=row)
conn.close()

How do you bind parameters in the Julia sqlite library?

I'm trying to use the Julia SQLite.jl library, but I can't figure out how to bind variables.
using SQLite
# Create DB and table
db = SQLite.DB("mydb.sqlite")
SQLite.createtable!(db, "Student", Tables.Schema((:Name, :Grade), (String, Int64)); temp=false, ifnotexists=true)
# Add vals
SQLite.execute(db, "INSERT INTO Student VALUES('Harry', 1)")
# Prepared statement: Can use: ?, ?NNN, :AAA, $AAA, #AAA
insert_stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(:N, :G)")
SQLite.bind!(insert_stmt, Dict("N"=>"George", "G"=>"4"))
# This fails, with error: SQLiteException("`:N` not found in values keyword arguments to bind to sql statement")
insert_stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(:N, :G)")
SQLite.bind!(insert_stmt, Dict(:N=>"George", :G=>"4"))
SQLite.execute(insert_stmt)
# This fails, with error: SQLiteException("values should be provided for all query placeholders")
insert_stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(?1, ?2)")
SQLite.bind!(insert_stmt, ["George", "4"])
SQLite.execute(insert_stmt)
# This fails, with error: SQLiteException("values should be provided for all query placeholders")
insert_stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(':N', ':G')")
SQLite.bind!(insert_stmt, Dict(:N=>"George", :G=>"4"))
SQLite.execute(insert_stmt)
# This doesn't bind, it inserts ':N' and ':G'
What's the right syntax? Thanks!
You could try:
stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(?, ?)")
DBInterface.execute(stmt, ["Jack",2])
Let's check if this worked:
julia> DBInterface.execute(db, "SELECT * FROM Student") |> DataFrame
2×2 DataFrame
Row │ Name Grade
│ String Int64
─────┼───────────────
1 │ Harry 1
2 │ Jack 2
(Similar to Przemyslaw Szufel's answer, just with named parameters like in the question.)
The documentation for DBInterface.execute (which the one for SQLite.execute recommends to be used) says:
DBInterface.execute(db::SQLite.DB, sql::String,
[params]) DBInterface.execute(stmt::SQLite.Stmt, [params])
Bind any positional (params as Vector or Tuple) or named (params as
NamedTuple or Dict) parameters to an SQL statement, given by db and
sql or as an already prepared statement stmt, execute the query and
return an iterator of result rows.
So you can pass on your Dict to execute directly as:
julia> insert_stmt = SQLite.Stmt(db, "INSERT INTO Student VALUES(:N, :G)")
julia> DBInterface.execute(insert_stmt, Dict(:N => "Palani", :G => 3))
SQLite.Query(SQLite.Stmt(SQLite.DB("mydb.sqlite"), 1), Base.RefValue{Int32}(101), Symbol[], Type[], Dict{Symbol, Int64}(), Base.RefValue{Int64}(0))

How do I solve Sqlite DB Index Error

Am working with Web2py and sqlite Db in Ubuntu. Iweb2py, a user input posts an item into an sqlite DB such as 'Hello World' as follows:
In the controller default the item is posted into ThisDb as follows:
consult = db.consult(id) or redirect(URL('index'))
form1 = [consult.body]
form5 = form1#.split()
name3 = ' '.join(form5)
conn = sqlite3.connect("ThisDb.db")
c = conn.cursor()
conn.execute("INSERT INTO INPUT (NAME) VALUES (?);", (name3,))
conn.commit()
Another code picks or should read the item from ThisDb, in this case 'Hello World' as follows:
location = ""
conn = sqlite3.connect("ThisDb.db")
c = conn.cursor()
c.execute('select * from input')
c.execute("select MAX(rowid) from [input];")
for rowid in c:break
for elem in rowid:
m = elem
c.execute("SELECT * FROM input WHERE rowid = ?", (m,))
for row in c:break
location = row[1]
name = location.lower().split()
my DB configuration for the table 'input' where Hello World' should be read from is this:
CREATE TABLE `INPUT` (
`NAME` TEXT
);
This code previously workd well while coding with windows7 and 10 but am having this problem ion Ubuntu 16.04. And I keep getting this error:
File "applications/britamintell/modules/xxxxxx/define/yyyy0.py", line 20, in xxxdefinition
location = row[1]
IndexError: tuple index out of range
row[0] is the value in the first column.
row[1] is the value in the second column.
Apparently, your previous database had more than one column.

equivalent to INSERT INTO TABLE SET in Oracle

I want to add data to table STATISTICS using INSERT statements.
I also want to move new counts to old counts and new date to old date as the new data comes in.
This is where it gets lil tricky because I don't know if there is such a thing as INSERT INTO table with SET in Oracle.
INSERT INTO STATISTICS
SET
MODEL = '&MY_MODEL',
NEW_COUNT =
(
SELECT COUNT(*)
FROM TABLE CLIENTS
),
NEW_DATE = SYSDATE,
OLD_COUNT = NEW_COUNT,
OLD_DATE = NEW_DATE,
PRNCT_CHANGE = ((NEW_COUNT) - (OLD_COUNT)) / (NEW_COUNT)*100
);
How do I accomplish this in Oracle?
This should upsert statistics, adding new ones as you go. It presumes a unique key on MODEL; if that's not true, then you'd have to do inserts as Angelina said, getting only the most recent row for a single MODEL entry.
MERGE INTO STATISTICS tgt
using (SELECT '&MY_MODEL' AS MODEL,
(SELECT COUNT(*) FROM CLIENTS) AS NEW_COUNT,
SYSDATE AS DATE_COUNT,
NULL AS OLD_COUNT,
NULL OLD_DATE,
NULL AS PRCNT_CHANGE
FROM DUAL) src
on (TGT.MODEL = SRC.MODEL)
WHEN MATCHED THEN UPDATE
SET TGT.NEW_COUNT = SRC.NEW_COUNT,
TGT.NEW_DATE = SRC.NEW_DATE,
TGT.OLD_COUNT = TGT.NEW_COUNT,
TGT.OLD_DATE = TGT.NEW_DATE,
TGT.PRCNT_CHG = 100 * (SRC.NEW_COUNT - TGT.NEW_COUNT) / (SRC.NEW_COUNT)
-- NEEDS DIV0/NULL CHECKING
WHEN NOT MATCHED THEN INSERT
(MODEL, NEW_COUNT, NEWDATE, OLD_COUNT, OLD_DATE, PRCNT_CHANGE)
VALUES
(src.MODEL, src.NEW_COUNT, src.NEWDATE, src.OLD_COUNT, src.OLD_DATE, src.PRCNT_CHANGE);
INSERT INTO STATISTICS(MODEL,NEW_COUNT,NEW_DATE,OLD_COUNT,OLD_DATE,PRNCT_CHANGE)
SELECT MODEL,
( SELECT COUNT(*)
FROM TABLE(USERS)
),
SYSDATE,
NEW_COUNT,
NEW_DATE,
(((NEW_COUNT) - (OLD_COUNT)) / (NEW_COUNT)*100)
FROM SEMANTIC.COUNT_STATISTICS
WHERE MODEL = '&MY_MODEL'
AND trunc(NEW_DATE) = trunc(NEW_DATE -1)
;

Copy a subset of column data from one table to another

I have two tables with identical schema. Let's name them TestTable and TestTableTemp. I need to copy just two columns from TestTableTemp to TestTable without disrupting other data. The rows in TestTable are a subset of those in TestTableTemp. Let's say the columns that I need to copy are named Column1 and Column2 and that they have identical primary keys reference by column primaryKey.
In mysql I believe this could be done as such or something similar:
UPDATE TestTable, TestTableTemp
SET TestTable.Column1 = TestTableTemp.Column1, TestTable.Column2 = TestTableTemp.Column2
WHERE TestTable.primaryKey = TestTableTemp.primaryKey
Sqlite does not allow for multiple tables to be defined on the update statement as can been seen in their reference data here: http://www.sqlite.org/lang_update.html
The best I could come up with is such:
UPDATE TestTable SET
Column1 = (select TestTableTemp.Column1 from TestTableTemp, TestTable where TestTable.primaryKey = TestTableTemp.primaryKey),
Column2 = (select TestTableTemp.Column2 from TestTableTemp, TestTable where TestTable.primaryKey = TestTableTemp.primaryKey)
WHERE EXISTS(select * from TestTableTemp where TestTable.primaryKey = TestTableTemp.primaryKey"
This gives me a syntax error near "." I am guessing this is because I cannot reference TestTable in the scalar expressions.
Can anyone point me in the right direction? Any help is much appreciated.
EDIT:
I cleaned up the second query a bit. It seems to just set the Column1 and Column2 to the first row from that column from TestTableTemp.
Your original query for comparison:
UPDATE TestTable, TestTableTemp
SET TestTable.Column1 = TestTableTemp.Column1
, TestTable.Column2 = TestTableTemp.Column2
WHERE TestTable.primaryKey = TestTableTemp.primaryKey
Here is the working query (I just slightly changed your version):
http://sqlfiddle.com/#!5/f3a19/9
UPDATE TestTable
SET
Column1 = ( SELECT TestTableTemp.Column1
FROM TestTableTemp
WHERE TestTableTemp.primaryKey = TestTable.primaryKey )
,Column2 = ( SELECT TestTableTemp.Column2
FROM TestTableTemp
WHERE TestTableTemp.primaryKey = TestTable.primaryKey )
WHERE EXISTS( SELECT NULL
FROM TestTableTemp
WHERE TestTableTemp.primaryKey = TestTable.primaryKey )
;

Resources