Python unpacking operator / unpack subquery in separated columns - sql

In Python there is the unpacking operator (*), which allows you to take an iterator or iterable (tuple, list, generator, etc.) and pass each of its items as an argument to a function. I want to do the same thing with a Postgresql subquery. But I can't find any information anywhere.
I want to do something like this:
INSERT INTO tabla1(a, b, c) SELECT a, *(SELECT b, c FROM tabla2 LIMIT 1) FROM tabla3
To avoid doing two almost identical selects and speed up my queries.
I want to AVOID something like this:
INSERT INTO tabla1(a, b, c) SELECT a, (SELECT b FROM tabla2 LIMIT 1), (SELECT c FROM tabla2 LIMIT 1) FROM tabla3
I tried the following:
review documentation
use with statement (It doesn't work for me because I can't relate a query column to the subquery, which would be necessary for me)
Read a question from this site (I don't have the link)
My question would be, is there something similar to that in Postgresql or any way to affect multiple columns with a single subquery? For example, something like the with statement with which you can do name_of_the_query.column?
Edit
This is the query I did with with, the test query with real names, I hope it makes my question better quality.
WITH ztabla02 AS (SELECT (CASE WHEN LEFT(maecuent.cuenta, 1) IN ('1','2','3') THEN
array[(SELECT descripcio FROM ztabla02 WHERE c_tabla='PR' AND c_clave=maecuent.cod_pcia), 'ARGENTINA']
ELSE
array['', (SELECT descripcio FROM ztabla02 WHERE c_tabla='PA' AND c_clave=maecuent.cod_pcia)]
END)
AS tuple)
SELECT ztabla02.tuple[1], ztabla02.tuple[2] FROM maecuent
Error:
ERROR: falta una entrada para la tabla «maecuent» en la cláusula FROM
LINE 1: WITH ztabla02 AS (SELECT (CASE WHEN LEFT(maecuent.cuenta, 1)...
^

You can do it with a CTE
with t2 as (
SELECT b, c FROM tabla2 LIMIT 1
)
INSERT INTO tabla1(a, b, c)
SELECT t3.a, t2.b, t2.c
FROM tabla3 t3
CROSS JOIN t2
Note LIMIT without ORDER BY will return an arbitrary row.

Related

How to extract a json value inside an array inside a json in SQL

I have a JSON being returned in my query called MetaDataJSON, inside which is an array of JSONs called Results. Inside each JSON in Results are two values, Chronic and Probability. There are a couple other tables that have been joined too. Is there a way to get Chronic in a column by itself? Right now I have gotten this far (table and variable names have been made generic):
SELECT DISTINCT
JSON_QUERY(mdj.value, '$.Results[0]') [Results]
FROM table1 t1
JOIN table2 t2 ON t2.parameter1 = t1.parameter1
AND t2.parameter2 = 'ASDF'
JOIN table3 t3 ON oad.parameter3 = oa.parameter3
AND t3.parameter4 = 11
CROSS APPLY OPENJSON(t3.MetaDataJSON) as mdj
This gets me a column called Results where each entry looks like:
{"Chronic": 0, "Probability": 0.0016}
Is there an efficient way to get Chronic in a column by itself? Thanks!
You can do it like this,
WITH jsons (x)
AS
(
-- replace this part with your query
Select a.x from (select '{"Chronic": 0, "Probability": 0.0016}' x ) as a, (SELECT 1 as y union select 2 as y ) as b
)
select
(SELECT value FROM OPENJSON(x,'$') where [key]='Chronic') as "Chronic",
(SELECT value FROM OPENJSON(x,'$') where [key]='Probability') as "Probability"
from jsons;
I think you can change the #json equation to use your query. But I cannot try since I don't have your tables...
BTW, I assume you are using MSSQL...

Oracle SQL - number of WITH clause column names does not match number of elements in select list

I have the following:
WITH Course_Skill(c_code, skillcode) AS (
SELECT c_code, skillcode
FROM course NATURAL JOIN taughtin),
CourseSet_Skill(csetID, skillcode) AS (
SELECT csetID, skillcode
FROM CourseSet CSet
JOIN Course_Skill CS ON CSet.c_code1=CS.c_code
UNION
SELECT csetID, skillcode
FROM CourseSet CSet
JOIN Course_Skill CS ON CSet.c_code2=CS.c_code
UNION
SELECT csetID, skillcode
FROM CourseSet CSet
JOIN Course_Skill CS ON CSet.c_code3=CS.c_code
),
/* more stuff */
I get the following error:
ORA-32038: number of WITH clause column names does not match number of elements in select list
Can anyone explain why this error occurs? The location of the error is stated as occurring in the first FROM clause after the CourseSet_Skill WITH clause. CourseSet_Skill is defined as having 2 columns (csetID & skillcode) and the select statements also only consist of 2 columns, which is the same amount.
UPDATE
The error was being caused by statement elsewhere in the
query. The error code just located it to this section of the query
for some reason. All is fixed and thank you all for your feedback.
When you have
with q(a,b) as (select x, y from ...
a and b provides aliases for x and y.
I must assume that one of your with clauses are like:
with q(a,b) as ( select x from ...
or
with q(a,b) as ( select x, y, z from...
such that the number of colums actually selected do not match the number of aliases.

How to use a variable AS a where clause?

I have one where clause which I have to use multiple times. I am quite new to Oracle SQL, so please forgive me for my newbe mistakes :). I have read this website, but could not find the answer :(. Here's the SQL statement:
var condition varchar2(100)
exec :condition := 'column 1 = 1 AND column2 = 2, etc.'
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from table_name
where category = X AND :condition
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3))
) A
,
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100)) as content
from table_name
where category = Y AND :condition
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100))) B
GROUP BY
a.content, b.content
The content field is a CLOB field and unfortunately all values needed are in the same column. My query does not work ofcourse.
You can't use a bind variable for that much of a where clause, only for specific values. You could use a substitution variable if you're running this in SQL*Plus or SQL Developer (and maybe some other clients):
define condition = 'column 1 = 1 AND column2 = 2, etc.'
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from table_name
where category = X AND &condition
...
From other places, including JDBC and OCI, you'd need to have the condition as a variable and build the query string using that, so it's repeated in the code that the parser sees. From PL/SQL you could use dynamic SQL to achieve the same thing. I'm not sure why just repeating the conditions is a problem though, binding arguments if values are going to change. Certainly with two clauses like this it seems a bit pointless.
But maybe you could approach this from a different angle and remove the need to repeat the where clause. Querying the table twice might not be efficient anyway. You could apply your condition once as a subquery, but without knowing your indexes or the selectivity of the conditions this could be worse:
with sub_table as (
select category, content
from my_table
where category in (X, Y)
and column 1 = 1 AND column2 = 2, etc.
)
Select a.content, b.content
from
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3)) as content
from sub_table
where category = X
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3))
) A
,
(Select (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100)) as content
from sub_table
where category = Y
group by (DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100))) B
GROUP BY
a.content, b.content
I'm not sure what the grouping is for - to eliminate duplicates? This only really makes sense if you have a single X and Y record matching the other conditions, doesn't it? Maybe I'm not following it properly.
You could also use a case statement:
select max(content_x), max(content_y)
from (
select
case when category = X
then DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,3) end as content_x,
case when category = Y
then DBMS_LOB.SUBSTR(ost_bama_vrij_veld.inhoud,100) end as content_y,
from my_table
where category in (X, Y)
and column 1 = 1 AND column2 = 2, etc.
)

Access substitute for EXCEPT clause

How can I get the same result I would get with the SQL code below in ms access? It does not recognize the EXCEPT clause...
SELECT DISTINCT
P.Name,
T.Training
FROM Prof AS P,
Training_done AS TC,
Trainings AS T
WHERE (P.Name Like '*' & NameProf & '*')
AND (P.Primary_Area = T.Cod_Area)
EXCEPT
SELECT DISTINCT
P.Name,
T.Training
FROM Prof AS P,
Training_done AS TC,
Trainings AS T
WHERE (P.Name Like '*' & NameProf & '*')
AND (P.Cod_Prof = TC.Cod_Prof);
Thanks in advance!
In order to get rid of the EXCEPT you could combine the conditions and negate the second one:
SELECT DISTINCT
P.Name,
T.Training
FROM Prof AS P,
Training_done AS TC,
Trainings AS T
WHERE ((P.Name Like '*' & NameProf & '*') AND
(P.Primary_Area = T.Cod_Area))
AND NOT ((P.Name Like '*' & NameProf & '*') AND
(P.Cod_Prof = TC.Cod_Prof));
SELECT A.x FROM A
EXCEPT
SELECT B.x FROM B
corresponds to
SELECT A.x FROM A
LEFT JOIN B
ON A.x = B.x
WHERE B.x IS NULL
use the find unmatched wizard in MS Access > Create > Query Wizard and you will get the following result
Union is a separate Access Query which i used to union a few tables instead of using sub queries
SELECT TableMain.Field1
FROM TableMain LEFT JOIN [Union] ON TableMain.[Field1] = Union.[field1]
WHERE (((Union.field1) Is Null));
Not an explicit example here, but consider UNION-ing the two fetched tables and selecting, from that union, pairs that have fewer than 2 instances of a certain field combination. This implies that, where each table has more than one instance of a record with the same values on the field combination, these records are the same and can be eliminated from result set. Where not, they are unique to one table, leaving fetch with only records from the selected table where there is no match to the other table. Kind of like a poor-man's "EXCEPT" KW.

How to find the occurrences of a column mapped to a corresponding column in a query SQL

I have a query as below
select custref, tetranumber
from
(select *
from cdsheader h, custandaddr c
where h.custref=c.cwdocid and c.addresstype = 'C' )
where tetranumber = '034096'
The objective is the 2nd column should have only one corresponding 1st column
Ex : 034096 should have always have 2600135 as the first column
I would like to check if there is any value apart from 2600135 for 034096.
(I am a java developer and suggested a solution to avoid 1 to n or n to n mappings of data but there is a bad data already in the DB(Oracle), so I would like to check whether there is a bad data so that I could delete the data)
re: The objective is the 2nd column should have only one corresponding 1st column
You'll need to perform an aggregate function, like MAX or MIN, to determine which of the row is returned.
Thanks for the response guys,
I have figured out the way and here it goes...
select custref, count(distinct(tetranumber)) from(
select custref, tetranumber from cdsheader h, custandaddr c where h.custref=c.cwdocid and c.addresstype = 'C')
group by custref having count(distinct(tetranumber))>1