My query has a NOT IN, and suddenly stopped showing results - google-bigquery

I have a query that runs every day, and suddenly it stopped outputting results. It doesn't output an error, just no results.
Note that this query includes a NOT IN operator.

This is a known problem of NOT IN behavior, check out the MySQL version of it:
MySQL "Not IN" query suddenly stopped returning results
With BigQuery:
WITH data AS (
SELECT * FROM UNNEST([1,2,3]) x
), data2 AS (
SELECT * FROM UNNEST([1,2]) x
)
SELECT * FROM data
WHERE x NOT IN (SELECT * FROM data2)
3
But then if you have a null in data2:
WITH data AS (
SELECT * FROM UNNEST([1,2,3]) x
), data2 AS (
SELECT * FROM UNNEST([1,2,null]) x
)
SELECT * FROM data
WHERE x NOT IN (SELECT * FROM data2)
# no results
Instead you could do a LEFT JOIN, or a NOT EXISTS:
WITH data AS (
SELECT * FROM UNNEST([1,2,3]) x
), data2 AS (
SELECT * FROM UNNEST([1,2]) x
)
SELECT * FROM data a
WHERE NOT EXISTS (SELECT * FROM data2 b WHERE a.x=b.x)
3

Related

BigQuery: Symmetric difference (xor) between two sets

BigQuery has UNION, INTERSECT, and EXCEPT [1], but not XOR.
SELECT * FROM [0, 1,2,3] XOR SELECT * FROM [2,3,4]
would return
0
1
4
As 0 and 1 are present in the first select but not second, and 4 is present in the second select, but not first.
I'd like to use it to find discrepancies between two tables, eg find customers that are present in one table, but not other and vice versa.
Any hints how to best do it?
[1] https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#set_operators
BigQuery does not need a XOR operator as it can be obtained from existing operators:
a first way to do so as #Genato points it out is to use JOIN like in this issue
Another way is to use set operators: A XOR B can be translated as (A AND NOT B) OR (B AND NOT A), so with your example you could write
(
SELECT * FROM UNNEST(ARRAY<int64>[0, 1, 2, 3]) AS number
EXCEPT DISTINCT SELECT * FROM UNNEST(ARRAY<int64>[2, 3, 4]) AS number)
UNION ALL
(
SELECT * FROM UNNEST(ARRAY<int64>[2,3,4]) AS number
EXCEPT DISTINCT SELECT * FROM UNNEST(ARRAY<int64>[0, 1, 2, 3]) AS number);
which results in:
Few 'workarounds'
Option 1
with table1 as (
select * from unnest([0, 1,2,3]) num
), table2 as (
select * from unnest([2,3,4]) num
)
select * from table1 where not num in (select num from table2)
union all
select * from table2 where not num in (select num from table1)
Option 2
with table1 as (
select * from unnest([0,1,2,3]) num
), table2 as (
select * from unnest([2,3,4]) num
)
select num from (
select distinct num from table1 union all
select distinct num from table2
)
group by num
having count(*) = 1
in both cases - output is

How to check result of a query using IF scripting in BigQuery?

I have a query and I want to check if the output has at least one row, if not , show some message like "No data". I have tried like described here : https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting#if
WITH
cte1 AS (
SELECT id, name
FROM My_table
)
SELECT
* from cte1;
IF (SELECT COUNT(*) = 0 FROM cte1) THEN SELECT "No data"; END IF
You can do something like this:
WITH cte1 AS (
SELECT id, name
FROM My_table
)
SELECT id, name
FROM cte1;
UNION ALL
SELECT NULL, 'No Data'
FROM (SELECT 1 as x) x
WHERE NOT EXISTS (SELECT 1 FROM cte2);
Note: The subqueries need to return the same columns.

find difference using UNION and minus

I am bit out of my wits why the sql below would not produce any row. Clearly there is an id 1 which is not in b and I expected that to be the output. I know I am missing some fundamentals on how union works - may be due to the fact that there is not output in the second minus?
Redshift:
WITh a as
(select 1 id union all select 2
)
,b as (select 2 id)
select * from a
minus
select * from b
union all
select * from b
minus
select * from a
Oracle-
WITh a as
(select 1 id from dual union all select 2 from dual
)
,b as (select 2 id from dual)
select * from a
minus
select * from b
union all
select * from b
minus
select * from a
There is an order of operations issue with the way you wrote your query. If you wrap the two sides of the union as subqueries, and select from them, then you get the result you expect:
select * from
(select * from a
minus
select * from b ) t1
union all
select * from
(select * from b
minus
select * from a ) t2
What appears to be happening is that first the following is run, leaving us with id=1:
select * from a
minus
select * from b
Then, this result is being unioned with a query on b:
(select * from a
minus
select * from b)
union all
select * from b
At this point, the result set again has both 1 and 2 in it. But now, we take a minus operation against table a:
(select * from a
minus
select * from b
union all
select * from b)
minus
select * from a
This results in an empty set, since (1,2) minus (1,2) leaves us with nothing.

How to call a sql query and pass a parameter from another table?

I have a complex sql query, named qryARAT2B_EXT.
SELECT
*
FROM
(
SELECT
*
FROM
(
SELECT
*,
firstStudy,
ABS(DATEDIFF('d', firstStudy, Check_Date)) as diff
FROM
(
SELECT
*,
(
SELECT
TOP 1 Check_Date
FROM
qryARAT2B
WHERE
PATNR = [PАРАМ]
ORDER BY
Check_Date
)
AS firstStudy
FROM
(
SELECT
*
FROM
qryARAT2B
WHERE
PATNR = [PАРАМ]
)
AS myPatientsWithStudy
)
AS myPatientsFirstStudy
)
WHERE
diff = 0
)
AS T1
LEFT JOIN
(
SELECT
*
FROM
(
SELECT
*,
firstStudy,
ABS(DATEDIFF('d', firstStudy, Check_Date)) as diff
FROM
(
SELECT
*,
(
SELECT
TOP 1 Check_Date
FROM
qryARAT2B
WHERE
PATNR = [PАРАМ]
ORDER BY
Check_Date
)
AS firstStudy
FROM
(
SELECT
*
FROM
qryARAT2B
WHERE
PATNR = [PАРАМ]
)
AS myPatientsWithStudy
)
AS myPatientsFirstStudy
)
WHERE
diff = 4
)
As T2
ON T1.PATNR = T2.PATNR
When I open it in ms-access, it asks for the value of the [PARAM] and produces the result.
I have a table of patients.
tblPatient with the columns:
PATNR, and s.o.
That contains the PATNR's of patients:
000001
000002
...
XXXXXX
I need to write sql to calculate data for all PATNR's at once.
something like this:
SELECT (SELECT * FROM qryARAT2B_EXT WHERE [PARAM] = PATNR) from tblPatient
But it is not accepted from ms-access. I'm not able to pass parameter to qryARAT2B_EXT from the SQL. Is there any specific syntax for it in ms-access?

(Oracle) Multiple WITH Clauses Referencing Each Other

We are rewriting a SQL script originally containing 6 CREATE/REPLACE VIEW's, because our new app can't create objects in the DB. To rewrite it, we are using the WITH keyword.
The problem is, the original views referenced each other. Will this be allowed in Oracle:
with
A as (select T1COL from Table1 ...),
B as (select NEWCOL from A ...) ,
..
The answer is: yes, it is possible.
Due to the large amount of code involved it's not feasible to quickly try it. One would hope a quick response wouldn't be too difficult
I've prepared a runnable test for you:
http://sqlfiddle.com/#!4/9eecb7d/7884
WITH
a AS ( SELECT 'A' as T1COL FROM dual ),
b AS ( SELECT * FROM a ),
c AS ( SELECT * FROM b ),
d AS ( SELECT * FROM c ),
e AS ( SELECT * FROM d ),
f AS ( SELECT * FROM e ),
g AS ( SELECT * FROM f ),
h AS ( SELECT * FROM g ),
i AS ( SELECT * FROM h ),
j AS ( SELECT * FROM i ),
k AS ( SELECT * FROM j ),
l AS ( SELECT * FROM k ),
m AS ( SELECT * FROM l ),
n AS ( SELECT * FROM m ),
o AS ( SELECT * FROM n ),
p AS ( SELECT * FROM o ),
q AS ( SELECT * FROM p )
SELECT * FROM q;