SqlAlchemy: proper way to do a bare exists query - sqlalchemy

I've the following construct which seems to produce the desired SQL:
>>> print session.query(exists('1').where(MyTable.name=='x'))
SELECT EXISTS (SELECT 1
FROM my_table
WHERE my_table.name = :name_1) AS anon_1
However, when I try to execute it with .scalar() or .all() it returns the error:
*** UnboundExecutionError: Could not locate a bind configured on SQL expression or this Session
How can I bind it for this simple query? I don't want to do bool(MyTable.query.filter(MyTable.name=='x').first()) as that wastefully pulls back the entire row from the table.
Update:
I've also tried:
>>> session.connection(mapper=MyTable).execute(
exists('1').where(MyTable.name=='x'))
StatementError: Not an executable clause 'EXISTS \
(SELECT 1 \nFROM my_table \nWHERE my_table.name = %(name_1)s)' []

Got it I think:
>>> session.connection(mapper=MyTable).execute(
select([exists('1').where(MyTable.name=='x')]))

Related

PostgreSQL 13.6 - Querying JSON resulting in "operator does not exist: json -> record"

I have json column inside my PostgreSQL table that looks something similar to this:
{"example--4--":"test 1","another example--6--":"test 2","final example--e35b172a-af71-4207-91be-d1dc357fe8f3--Equipment":"ticked"}
{"example--4--":"test 4","another example--6--":"test 5","final example--e35b172a-af71-4207-91be-d1dc357fe8f3--Equipment":"ticked"}
Each key contains a map which is separated by --. The prefix is unique, ie: "example", "another example" and "final example".
I need to query on the unique prefix and so far, nothing I'm trying is even close.
select some_table.json_column from some_table
left join lateral (select array(select * from json_object_keys(some_table.json_column) as keys) k on true
where (select SPLIT_PART(k::text, '--', 1) as part_name) = 'example'
and some_table.json_column->>k = 'test 1'
The above is resulting in the following error (last line):
operator does not exist: json -> record
My expected output would be any records where "example--4--":"test 1" is present (in my above example, the only result would be)
{"example--4--":"test 1","another example--6--":"test 2","final example--e35b172a-af71-4207-91be-d1dc357fe8f3--Equipment":"ticked"}
Any help appreciated. After debugging around for a while, I can see the main issue resolves in the implicit cast to ::text. k seems to be a "record" of the keys that I need to loop and split to compare, currently, I'm casting a record to text which is causing the issue.
One way to do it, is to use an EXIST condition together with jsonb_each_text()
select *
from the_table
where exists (select *
from jsonb_each_text(data) as x(key,value)
where x.key like 'example%'
and x.value = 'test 1')
If your column isn't a jsonb (which it should be), you need to use json_each_text() instead
Another option is to use a JSON path expression:
select *
from the_table
where data #? '$.keyvalue() ? (#.key like_regex "^example" && #.value == "test 1")'

Postgresql test JSON and delete

I have a PGSQL database with a table that contains column containingJSON data along the lines of
{"kind":2,"msgid":102}
{"kind":99,"pid":"39s-8KeH306vhjzNta3Yrg,,","msgid":101}
...
Is it possible to write and execute DELETE statement along the lines of
DELETE FROM table WHERE data.kind = '99' AND data.pid = '39s-8KeH306vhjzNta3Yrg,,'?
where data happens to be the name of that particular column. I tried the above and got the error
missing FROM-clause entry for table "data"
i.e. PGSQL is interpreting that as being the table data. Clearly, the require syntax is different. I'd be grateful to anyone who might be able to tell me what to do here.
assuming you have:
t=# with c(j) as (values('{"kind":99,"pid":"39s-8KeH306vhjzNta3Yrg,,","msgid":101}'::json))
select * from c where j->>'kind' = '99' and j->>'pid' = '39s-8KeH306vhjzNta3Yrg,,';
j
----------------------------------------------------------
{"kind":99,"pid":"39s-8KeH306vhjzNta3Yrg,,","msgid":101}
(1 row)
then your statement will be:
delete from table where data->>'kind' = '99' and data->>'pid' = '39s-8KeH306vhjzNta3Yrg,,';
check json operators here: https://www.postgresql.org/docs/current/static/functions-json.html

Postgresql update json data property

I created a field name is result and type is text. I just want to update 'lat' in column. When I use this query I get syntax error. How can I do?
The column data is
"{"lat":"48.00855","lng":"58.97342","referer":"https:\/\/abc.com\/index.php"}"
Query is
update public.log set (result::json)->>'lat'=123 where id=6848202
Syntax error is
ERROR: syntax error at or near "::"
Use the jsonb concatenation operator (Postgres 9.5+):
update log
set result = result::jsonb || '{"lat":"123"}'
where id = 6848202
In Postgres 9.4 use json_each() and json_object_agg() (because jsonb_object_agg() does not exists in 9.4).
update log
set result = (
select json_object_agg(key, case key when 'lat' then '123' else value end)
from json_each(result)
)
where id = 6848202
Both solutions assume that the json column is not null. If it does not contain the lat key, the first query will create it but the second will not.
In PostgreSQL 13, You can:
update public.log set result = jsonb_set(result,'{lat}','"123"') where id=6848202;
In case the column is still null, you can use coalesce. The answer is provided here: PostgreSQL 9.5 - update doesn't work when merging NULL with JSON
I also tried to update json value in json type field, but couldn't find appropriate example. So I've connected to postgres DB using PgAdmin4, opened desired table and changed desired field's value, then looked at Query History to see what command it uses to change it.
So, finally, I've got the next simple python code for own purposes to update json field in postgres db:
import psycopg2
conn = psycopg2.connect(host='localhost', dbname='mydbname', user='myusername', password='mypass', port='5432')
cur = conn.cursor()
cur.execute("UPDATE public.mytable SET options = '{\"credentials\": \"required\", \"users\": [{\"name\": \"user1\", \"type\": \"string\"}]}'::json WHERE id = 8;")
cur.execute("COMMIT")

MySQL Query gets too complex for me

I'm trying to write a MYSQL Query that updates a cell in table1 with information gathered from 2 other tables;
The gathering of data from the other 2 tables goes without much issues (it is slow, but that's because one of the 2 tables has 4601537 records in it.. (because all the rows for one report are split in a separate record, meaning that 1 report has more than 200 records)).
The Query that I use to Join the two tables together is:
# First Table, containing Report_ID's: RE
# Table that has to be updated: REGI
# Join Table: JT
SELECT JT.report_id as ReportID, REGI.Serienummer as SerialNo FROM Blancco_Registration.TrialTable as REGI
JOIN (SELECT RE.Value_string, RE.report_id
FROM Blancco_new.mc_report_Entry as RE
WHERE RE.path_id=92) AS JT ON JT.Value_string = REGI.Serienummer
WHERE REGI.HardwareType="PC" AND REGI.BlanccoReport=0 LIMIT 100
This returns 100 records (I limit it because the database is in use during work hours and I don't want to steal all resources).
However, I want to use these results in a Query that updates the REGI table (which it uses to select the 100 records in the first place).
However, I get the error that I cannot select from the table itself while updateing it (logically). So I tried selecting the select statement above into a temp table and than Update it; however, then I get the issue that I get to much results (logically! I only need 1 result and get 100) however, I'm getting stuck in my own thougts.. I ultimately need to fill the ReportID into each record of REGI.
I know it should be possible, but I'm no expert in MySQL.. is there anybody that can point me into the right direction?
Ps. fixing the table containing 400k records is not an option, it's a program from an external developer and I can only read that database.
The errors I'm talking about are as follows:
Error Code: 1093. You can't specify target table 'TrialTable' for update in FROM clause
When I use:
UPDATE TrialTable SET TrialTable.BlanccoReport =
(SELECT JT.report_id as ReportID, REGI.Serienummer as SerialNo FROM Blancco_Registration.TrialTable as REGI
JOIN (SELECT RE.Value_string, RE.report_id
FROM Blancco_new.mc_report_Entry as RE
WHERE RE.path_id=92) AS JT ON JT.Value_string = REGI.Serienummer
WHERE REGI.HardwareType="PC" AND REGI.BlanccoReport=0 LIMIT 100)
WHERE TrialTable.HardwareType="PC" AND TrialTable.BlanccoReport=0)
Then I tried:
UPDATE TrialTable SET TrialTable.BlanccoReport = (SELECT ReportID FROM (<<and the rest of the SQL>>> ) as x WHERE X.SerialNo = TrialTable.Serienummer)
but that gave me the following error:
Error Code: 1242. Subquery returns more than 1 row
Haveing the Query above with a LIMIT 1, gives everything the same result
Firstly, your query seems to be functionally identical to the following:
SELECT RE.report_id ReportID
, REGI.Serienummer SerialNo
FROM Blancco_Registration.TrialTable REGI
JOIN Blancco_new.mc_report_Entry RE
ON RE.Value_string = REGI.Serinummer
WHERE REGI.HardwareType = "PC"
AND REGI.BlanccoReport=0
AND RE.path_id=92
LIMIT 100
So, why not use that?
EDIT:
I still don't get it. I can't see what part of the problem the following fails to solve...
UPDATE TrialTable REGI
JOIN Blancco_new.mc_report_Entry RE
ON RE.Value_string = REGI.Serinummer
SET TrialTable.BlanccoReport = RE.report_id
WHERE REGI.HardwareType = "PC"
AND REGI.BlanccoReport=0
AND RE.path_id=92;
(This is not an answer, but maybe a pointer towards a few points that need further attention)
Your JT sub query looks suspicious to me:
(SELECT RE.Value_string, RE.report_id
FROM Blancco_new.mc_report_Entry as RE
WHERE RE.path_id=92
GROUP BY RE.report_id)
You use group by but don't actually use any aggregate functions. The column RE.Value_string should strictly be something like MAX(RE.Value_string) instead.

Django select distinct in mysql

How would I do the following query in django:
Asset.objects.all().distinct('checksum') # get all distinct checksum items
The equivalent in SQL would be:
SELECT * FROM asset GROUP BY checksum
Note that I need all fields here, so I cannot do something like Asset.objects.values_list('checksum').distinct(). How would I do this?
Do you want to get the first item of every checksum?
items = Asset.objects.all()
items.query.group_by = ['checksum']
print items
[<Asset: ...]