How to create update query with QSqlQuery - python-3.x

I'm trying to create an update query in Python3/PyQt5.10/Sqlite . A select/insert query made the same way runs fine. Fields & corresponding record exist.
def updateRecords():
theDict = {
"Loc": "PyQt121",
"BoekNr" : "dfdf",
"BoekTitel" : "eeee",
"BoekBedrag" : 999
}
theFilter = " WHERE Loc = 'PyQt'"
query = QSqlQuery()
columns = ', '.join(pDict.keys())
placeholders = ':'+', :'.join(pDict.keys())
sql = 'UPDATE %s SET (%s) VALUES (%s) %s' % (pTable, columns, placeholders, pFilter)
query.prepare(sql)
for key, value in pDict.items():
query.bindValue(":"+key, value)
print (sql)
query.exec_()
print(query.lastError().databaseText())
return query.numRowsAffected()
The sql generated is UPDATE tempbooks SET (Loc, BoekNr, BoekTitel, BoekBedrag) VALUES (:Loc, :BoekNr, :BoekTitel, :BoekBedrag) WHERE Loc = 'PyQt'.
query.lastError().databaseText()) give me "No Query" and updated rows is -1.

The correct syntax for an update query:
UPDATE tablename
set col1 = val1,
col2 = val2,
col3 = val3
WHERE condition
Probably query.prepare(sql) is returning False because of invalid syntax.

Related

How to insert/update postgresql table using WHERE clause?

I'm using pscopg2 module to write into my database (postgresql). I'm trying to insert or update a column/row value based on an equivalence statement such as:
INSERT x INTO TABLE A WHERE variable_x MATCHES/EQUAL TO value y IN SAME TABLE;
Code:
def update_existing_record(dev_eui, device_serial_num):
cur = con.cursor()
con.autocommit = True
sql_command = " IF EXISTS (dev_eui == %s) SET severn_db.device_serial_num VALUES (%s)"
#sql_command = "INSERT INTO severn_db (device_serial_num) WHERE EXISTS (dev_eui == dev_eui) VALUES (%s) "
sql_values = (dev_eui, device_serial_num)
cur.execute(sql_command, sql_values,)
cur.close()
All I am trying to do is insert or update table column that matches the condition x == y (where x would be a parameter passed in as a local variable to the python function).
Any help?

Power Query - How to pass blank Excel cell as NULL value?

I have SQL that looks like this, which works fine in SSMS:
DECLARE #pPart VARCHAR(100) = '00039',
#pColor VARCHAR(100) = '01816'
SET #pPart = ISNULL(#pPart,'-1')
SET #pColor = ISNULL(#pColor,'-1')
SELECT *
FROM myTable
WHERE (PartID IN (SELECT (#pPart)) OR #pPart = '-1')
AND (ColorID IN (SELECT (#pColor)) OR #pColor = '-1')
If I change either value (or both values) in the DECLARE from a value to NULL, the code returns the results I expect. I'm just not sure how to make this work within Power Query. If both cells are populated with values, the query works. If I delete the value from either cell, it's just returning a list of all the tables in my database (weird...).
I created a named range called "GetValues" that covers B2:B3 and looks like this:
Name
Value
Part
00039
Color
01816
In the Advanced Editor of Power Query, my query looks like this:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
pColor = Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SET #pPart = ISNULL(#pPart,'-1')
SET #pColor = ISNULL(#pColor,'-1')
SELECT *
FROM myTable
WHERE (PartID IN (SELECT (#pPart)) OR #pPart = '-1')
AND (ColorID IN (SELECT (#pColor)) OR #pColor = '-1')
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
I tried changing my SET lines, which also works in SSMS if I change a value to '' or ' ' but still returns a list of all tables in my DB in Power Query. I'm trimming the strings in case the user put a space in the cells instead of leaving them blank:
IF LTRIM(RTRIM(#pPart)) = '' SET #pPart = '-1'
IF LTRIM(RTRIM(#pColor)) = '' SET #pColor = '-1'
So how do I pass a blank cell as NULL or at least as '' ?
EDIT: I also tried stripping my query down to the bare bones to see what parameters are being passed. This query successfully returns the value in B2.
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"'
SELECT #pPart
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
Now I want to see what happens when I include the blank cell B3:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = Source{1}[Column1],
pColor = Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SELECT #pPart, #pColor
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target
This query also returned a list of all the tables in my database.
I also tried changing
in
Target
to
in
pColor
and the query preview shows null in all lowercase, which makes me think it's indeed returning a null value. I just can't figure out how to make this work.
If the goal is to treat blank cell values as a wildcard then this will work: first remove the SET statements then use this sql:
SELECT *
FROM myTable
WHERE (PartID = #pPart OR #pPart is null OR TRIM(#pPart) ='')
AND (ColorID = #pColor OR #pColor is null OR TRIM(#pColor) ='')
You would get:
Alll rows only if both variables are blank.
No rows if #pPart is not null/blank and has no matches
No rows if #pColor is not null/blank and has no matches
You could add this condition to prevent returning any rows when both inputs are blank/ null:
AND ( ISNULL(TRIM(pPart), '') <> '' OR ISNULL(TRIM(pColor), '') <> '')
To get this to work, I had to address the null values before the query started. For whatever reason (EDIT: Jeroen gives the actual reason in the comment below), passing pPart or pColor as NULL would just return a list of tables and didn't actually pass the NULL value. Here's what seems to be working:
let
Source = Excel.CurrentWorkbook(){[Name="GetValues"]}[Content],
pPart = if Source{1}[Column1] = null then "-1" else Source{1}[Column1],
pColor = if Source{2}[Column1] = null then "-1" else Source{2}[Column1],
Query = "
DECLARE #pPart VARCHAR(100) = '"& pPart &"',
#pColor VARCHAR(100) = '"& pColor &"'
SELECT *
FROM myTable
WHERE (PartID= '" & pPart & "' OR " & pPart & " = '-1')
AND (ColorID = '" & pColor & "' OR " & pColor & " = '-1')
",
Target = Sql.Database("myServer", "myDatabase", [Query=Query])
in
Target

How return details of updated row?

I have database in MS Access 2016, and want to run update query thru Excel VBA - this works. After this I want to return details of updated row (values from two columns - ID, Col1). Now I have only number of affected rows. How to achive this?
My query:
UPDATE
(SELECT TOP 1 ID, Col1, Update_time, Update_user
FROM Table1
WHERE Update_user Is Null
ORDER BY Col2 DESC , ID) AS U_ROW
SET U_ROW.Update_time = Now(), U_ROW.Update_user = [username];
In Excel VBA I run it thru ADODB.Command:
With baseRecordsetCommand
.ActiveConnection = objectConnection
.CommandType = adCmdStoredProc
.CommandText = "qryTest"
.NamedParameters = True
.Parameters.Append .CreateParameter("#username", adVarChar, adParamInput, 255, LCase(Environ("Username")))
.Execute recordsAffected
End With
Usually these kind of ops goes into a stored procedure but in Ms Acces/Excel you have to use VBA. Easiest way is, to retrieve the Id you are about to update before you the update.
So this comes first: save it in a variable
SELECT TOP 1 ID
FROM Table1
WHERE Update_user Is Null
ORDER BY Col2 DESC , ID
And then
update Table1
SET Table1.Update_time = Now(), Table1.Update_user = #username where Id = #idFromFirstQuery;
followed by
select * from Table1 where Id = #idFromFirstQuery;
in this way you know what Id, row you are updating.
OR:
you can turn the now() also into a parameter and supply a timestamp as parameter.
like:
update (table selection )
set update_time = '2020-19-03 10:0=10:10', update_user = 'User1';
after update you can do something like:
Select *
from Table1
where update_user = 'User1' and update_time = '2020-19-03 10:0=10:10';
NOTE!! you are highly assuming the timestamp you are supplying + username is unique. I personally would not use this method.
Not sure on this, but if you have a unique id, you could do something like this. This was done in Access, so the connection would need to be set up, as i believe this is ok.
Function sqlret() As String
Dim c As ADODB.Connection
Dim s As String
Dim r As ADODB.Recordset
Dim l As Long
Set c = CurrentProject.Connection
c.Execute "insert into tblprojects(projecttitle) values ('code1')"
Set r = New ADODB.Recordset
r.Open "select ##identity", c, 1
l = r.Fields(0).Value
r.Close
r.Open "select * from tblprojects where [projectid]=" & l, c, 1
sqlret = r.GetString
End Function

how to fix this dict and postgreSQL

i just want to update my keys,values from my dict
this is for updating PostgreSQL using python dict
data ={
'created_by':'obama',
'last_updated_by':'nandu',
'effective_from':'2019-12-30',
'effective_to':'2017-12-30'
}
lst= list()
lst1 = list()
for key,value in data.items():
lst.append(key)
lst1.append(value)
keys = tuple(lst)
values = tuple(lst1)
update = "UPDATE table_name SET %s = %s where name = 'kumar'"
cur.execute(update,(keys,values))
i want to set keys as field name and values as values
but i am getting the field names(keys) as string
so i am getting syntax error
You cannot use tuples for SET. Best is to loop over the dict and set each key one at the time:
data ={'created_by':'obama',
'last_updated_by':'nandu',
'effective_from':'2019-12-30',
'effective_to':'2017-12-30',
}
for key, value in data.items():
update = "UPDATE table_name SET %s = %s where name = 'kumar'"
cur.execute(update,(key, value))
or following the suggestion using f-strings
data ={'created_by':'obama',
'last_updated_by':'nandu',
'effective_from':'2019-12-30',
'effective_to':'2017-12-30',
}
arguments = ','.join([f'{key}=\'{val}\'' for key, val in data.items()])
update = f"UPDATE table_name SET {arguments} where name = 'kumar'"
cur.execute(update)

update statement using loop over tuple of query and data fails in psycopg2

I have created a mini functional pipeline which creates an update statement with regex and then passes the statement and the data to pycopg2 to execute.
If I copy paste the statement outside of the loop it works, if I try to loop over all statements I get an error.
# Function to create statement
def psycopg2_regex_replace_chars(table, col, regex_chars_old, char_new):
query = "UPDATE {} SET {} = regexp_replace({}, %s , %s, 'g');".format(table, col, col)
data = (regex_chars_old, char_new)
return (query, data)
# Create functions with intelligible names
replace_separators_with_space = partial(psycopg2_regex_replace_chars,regex_chars_old='[.,/[-]]',char_new=' ')
replace_amper_with_and = partial(psycopg2_regex_replace_chars, regex_chars_old='&', char_new='and')
# create funcs_list
funcs_edit = [replace_separators_with_space,
replace_amper_with_and]
So far, so good.
This works
stmt = "UPDATE persons SET name = regexp_replace(name, %s , %s, 'g');"
data = ('[^a-zA-z0-9]', ' ')
cur.execute(stmt, data)
conn.commit()
This fails
tables = ["persons"]
cols = ["name", "dob"]
for table in tables:
for col in cols:
for func in funcs_edit:
query, data = func(table=table, col=col)
cur.execute(query, data)
conn.commit()
error
<ipython-input-92-c8ba5d469f88> in <module>
6 for func in funcs_edit:
7 query, data = func(table=table, col=col)
----> 8 cur.execute(query, data)
9 conn.commit()
ProgrammingError: function regexp_replace(date, unknown, unknown, unknown) does not exist
LINE 1: UPDATE persons SET dob = regexp_replace(dob, '[.,/[-]]' , ' ...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.```

Resources