BigQuery - create a table and populate with data - google-bigquery

With BigQuery is it possible to set up and populate data into a table defined as part of a 'WITH...' statement?
Like...
> with table1 as (
select id,title from (
> {1,'Fred'),
> {2,'Joe'),
> {3,'Mary'), ) as tt )

with table1 as (
select 1 as id, 'Fred' as title union all
select 2, 'Joe' union all
select 3, 'Mary'
)
select * from table1

Related

Biq Query - Count

I have table that displays
ID employeename Supervisorname
Need to display another column CountD: count of employee for the direct supervior,CountI which shows the count of employee indirect
Snapshot sharedenter image description here
Tried Count (*) over partition by Supervisorname but didnot help
Below is for BigQuery Standard SQL
Try below script
#standardSQL
DECLARE rows_count, run_away_stop INT64 DEFAULT 0;
CREATE TEMP TABLE input AS (
SELECT 1 id, 'A' employee, 'X' supervisor UNION ALL
SELECT 2, 'B', 'X' UNION ALL
SELECT 3, 'C', 'X' UNION ALL
SELECT 4, 'X', 'F' UNION ALL
SELECT 5, 'Y', 'F' UNION ALL
SELECT 6, 'F', 'G'
);
CREATE TEMP TABLE ttt AS SELECT supervisor, employee FROM input;
LOOP
SET (rows_count, run_away_stop) = ((SELECT COUNT(1) FROM ttt), run_away_stop + 1);
CREATE OR REPLACE TEMP TABLE ttt AS
SELECT supervisor, employee FROM ttt UNION DISTINCT
SELECT t1.supervisor, t2.employee
FROM input t1 JOIN ttt t2
ON t1.employee = t2.supervisor;
IF rows_count = (SELECT COUNT(1) FROM ttt) OR run_away_stop > 10 THEN BREAK; END IF;
END LOOP;
SELECT t1.*,
IFNULL(direct_employees, 0) AS direct_employees,
IFNULL(all_employees, 0) AS all_employees
FROM input t1
LEFT JOIN (
SELECT supervisor, COUNT(1) direct_employees
FROM input GROUP BY supervisor
) t2 ON t1.employee = t2.supervisor
LEFT JOIN (
SELECT supervisor, COUNT(1) all_employees
FROM ttt GROUP BY supervisor
) t3 ON t1.employee = t3.supervisor
ORDER BY 1;
it returns desired output
To apply to your real table
Remove CREATE TEMP TABLE input AS ( ... ) statement
Instead of input table use your real table reference as your_project.your_dataset.your_table
Also, take attention to run_away_stop > 10 expression - it takes care of loop running not more that 10 times - you can tune this number based on how deep hierarchy in your data
As an option - you can try use Array instead of Temp table as in example below
#standardSQL
DECLARE rows_count, run_away_stop INT64 DEFAULT 0;
DECLARE ttt ARRAY<STRUCT<supervisor STRING, employee STRING>> DEFAULT [];
CREATE TEMP TABLE input AS (
SELECT 1 id, 'A' employee, 'X' supervisor UNION ALL
SELECT 2, 'B', 'X' UNION ALL
SELECT 3, 'C', 'X' UNION ALL
SELECT 4, 'X', 'F' UNION ALL
SELECT 5, 'Y', 'F' UNION ALL
SELECT 6, 'F', 'G'
);
SET ttt = ARRAY(SELECT AS STRUCT supervisor, employee FROM input);
LOOP
SET (rows_count, run_away_stop) = (ARRAY_LENGTH(ttt), run_away_stop + 1);
SET ttt = ARRAY(
SELECT AS STRUCT * FROM (
SELECT supervisor, employee FROM UNNEST(ttt) UNION DISTINCT
SELECT t1.supervisor, t2.employee
FROM input t1 JOIN UNNEST(ttt) t2
ON t1.employee = t2.supervisor
));
IF rows_count = ARRAY_LENGTH(ttt) OR run_away_stop > 10 THEN BREAK; END IF;
END LOOP;
SELECT t1.*,
IFNULL(direct_employees, 0) AS direct_employees,
IFNULL(all_employees, 0) AS all_employees
FROM input t1
LEFT JOIN (
SELECT supervisor, COUNT(1) direct_employees
FROM input GROUP BY supervisor
) t2 ON t1.employee = t2.supervisor
LEFT JOIN (
SELECT supervisor, COUNT(1) all_employees
FROM UNNEST(ttt) GROUP BY supervisor
) t3 ON t1.employee = t3.supervisor
ORDER BY 1;

Merge three tables in Select query by rule 3, 2, 1 records from each table

Merge three tables in a Select query by rule 3, 2, 1 records from each table as follows:
TableA: ID, FieldA, FieldB, FieldC,....
TableB: ID, FieldA, FieldB, FieldC,....
TableC: ID, FieldA, FieldB, FieldC,....
ID : auto number in each table
FieldA will be unique in all three tables.
I am looking for a Select query to merge three tables as follows:
TOP three records from TableA sorted by ID
TOP two records from TableB sorted by ID
TOP 1 record from TableC sorted by ID
Repeat this until select all records from all three tables.
If some table has fewer records or does not meet the criteria, ignore that and continue with others.
My attempt:
I did it totally through programming way, like cursors and If conditions inside a SQL Server stored procedure.
It makes delay.
This requires a formula that takes row numbers from each table and transforms it into a series of integers that skips the desired values.
In the query below, I am adding some CTE for the sake of shortening the formula. The real magic is in the UNION. Also, I am adding an additional field for your control. Feel free to get rid of it.
WITH A_Aux as (
SELECT 'A' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableA.*
FROM TableA
), B_Aux AS (
SELECT 'B' As FromTable, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum, TableB.*
FROM TableB
), C_Aux AS (
SELECT 'C' As FromTable, ROW_NUMBER() OVER (Order BY ID) AS RowNum, TableC.*
FROM TableC
)
SELECT *
FROM (
SELECT RowNum+3*FLOOR((RowNum-1)/3) As ColumnForOrder, A_Aux.* FROM A_Aux
UNION ALL
SELECT 3+RowNum+4*FLOOR((RowNum-1)/2), B_Aux.* FROM B_Aux
UNION ALL
SELECT 6*RowNum, C_Aux.* FROM C_Aux
) T
ORDER BY ColumnForOrder
PS: note the pattern Offset + RowNum + (6-N) * Floor((RowNum-1)/N) to group N records together (it of course simplifies a lot for TableC).
PPS: I don't have a SQL server at hand to test it. Let me know if there is a syntax error.
You may try this..
GO
select * into #temp1 from (select * from table1) as t1
select * into #temp2 from (select * from table2) as t2
select * into #temp3 from (select * from table3) as t3
select * into #final from (select col1, col2, col3 from #temp1 where 1=0) as tb
declare #i int
set #i=1
while( (select COUNT(*) from #temp1)>#i)
Begin
;with ct1 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp1
),ct2 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp2
),ct3 as (
select ROW_NUMBER() over (order by id) as Slno, * from #temp3
),cfinal as (
select top 3 * from #temp1
union all
select top 2 * from #temp2
union all
select top 1 * from #temp3
)
insert into #final ( col1 , col2, col3 )
select col1, col2, col3 from cfinal
delete from #temp1 where id in (select top 3 ID from #temp1)
delete from #temp2 where id in (select top 2 ID from #temp2)
delete from #temp3 where id in (select top 1 ID from #temp3)
set #i = #i+1
End
Select * from #final
Drop table #temp1
Drop table #temp2
Drop table #temp3
GO
First create temp table for all 3 tables with each insert delete the inserted record and this will result you the desired result, if nothing is missing from my side.
Please see to this if this works.
There is not a lot of information to go with here, but I assume you can use UNION to combine multiple statements.
SELECT * TableA ORDER BY ID DESC OFFSET 3 ROWS
UNION
SELECT * TableB ORDER BY ID DESC OFFSET 2 ROWS
UNION
SELECT * TableC ORDER BY ID DESC OFFSET 1 ROWS
Execute and see if this works.
/AF
From my understanding, I create three temp tables as ta, tb, tc.
select * into #ta from (
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
union all
select 'A' a
) a
select * into #tb from (
select 'B' b
union all
select 'B'
union all
select 'B'
union all
select 'B'
union all
select 'B'
) b
select * into #tc from (
select 'C' c
union all
select 'C'
union all
select 'C'
union all
select 'C'
union all
select 'C'
) c
If tables match you tables, then the output looks like A,A,A,B,B,C,A,A,A,B,B,C,A,B,C,C,C
T-SQL
declare #TAC int = (select count (*) from #ta) -- Table A Count = 7
declare #TBC int = (select count (*) from #tb) -- Table B Count = 5
declare #TAR int = #TAC % 3 -- Table A Reminder = 1
declare #TBR int = #TBC % 2 -- Table B Reminder = 1
declare #TAQ int = (#TAC - #TAR) / 3 -- Table A Quotient = (7 - 1) / 3 = 2, is will passed on NTILE
-- So we gonna split as two group (111), (222)
declare #TBQ int = (#TBC - #TBR) / 2 -- Table B Quotient = (5 - 1) / 2 = 2, is will passed on NTILE
-- So we gonna split as two group (11), (22)
select * from (
select *, NTILE (#TAQ) over ( order by a) FirstOrder, 1 SecondOrder from (
select top (#TAC - #TAR) * from #ta order by a
) ta -- 6 rows are obtained out of 7.
union all
select *, #TAQ + 1, 1 from (
select top (#TAR) * from #ta order by a desc
) ta -- Remaining one row is obtained. Order by desc is must
-- Here FirstOrder is next value of previous value.
union all
select *, NTILE (#TBQ) over ( order by b), 2 from (
select top (#TBC - #TBR) * from #tb order by b
) tb
union all
select *, #TBQ + 1, 2 from (
select top (#TBR) * from #tb order by b desc
) tb
union all
select *, ROW_NUMBER () over (order by c), 3 from #tc
) abc order by FirstOrder, SecondOrder
Let me explain the T-SQL:
Before that, FYR: NTILE and Row Number
Get the count.
Find the Quotient which will pass to NTILE function.
Order by the NTILE value and static.
Note:
I am using SQL Server 2017.
If T-SQL works fine, then you need to change the column in order by <yourcolumn>.

Exists - Not exists - Exclude records those are having status in 0 ignoring other status associated with that record

Below is my data.
with cte as(
select 'A' name, 0 status
union all select 'A' name, 1 status
union all select 'B' name, 1 status
union all select 'C' name, 2 status
union all select 'D' name, 1 status
)
I want to get only B, C, D as output from the query. Lets say, 0 is status-complete & I want to ignore records associated with it.
This I am able to achieve using the not in clause as below.
select * from cte c
where c.name not in (select cf.name from cte cf where cf.status=0)
But I want to achieve this using exists or not exists clause in where condition.
Could you please share the logic ?
thanks,
Can you please try with this:
SELECT * FROM cte c
WHERE NOT EXISTS (SELECT cf.name
FROM cte cf WHERE c.name = cf.name AND cf.status = 0)
For this we don't need any column in the where clause because we are addressing that conditional column as comparison in WHERE of sub query.
Please try this
with cte as(
select 'A' name, 0 status
union all select 'A' name, 1 status
union all select 'B' name, 1 status
union all select 'C' name, 2 status
union all select 'D' name, 1 status
)
Select * from cte c
where NOT EXISTS (select 1 from cte cf where cf.status=0 AND c.name = cf.name)
With NOT EXISTS
with cte as(
select 'A' name, 0 status
union all select 'A' name, 1 status
union all select 'B' name, 1 status
union all select 'C' name, 2 status
union all select 'D' name, 1 status
)
select * from cte out where NOT EXISTS
(select inn.name from cte inn WHERE out.name = inn.name and inn.status=0)
DECLARE #tbl1 AS TABLE
(
Name VARCHAR(50),
Status INT
)
INSERT INTO #tbl1 VALUES('A',0)
INSERT INTO #tbl1 VALUES('A',1)
INSERT INTO #tbl1 VALUES('B',1)
INSERT INTO #tbl1 VALUES('C',1)
INSERT INTO #tbl1 VALUES('D',1)
INSERT INTO #tbl1 VALUES('E',0)
With Not EXISTS:
SELECT
*
FROM #tbl1 T1
WHERE NOT EXISTS( SELECT T2.Name FROM #tbl1 T2 WHERE T2.Status=0 AND T1.Name=T2.Name)
With EXISTS:
SELECT
*
FROM #tbl1 T1
WHERE EXISTS( SELECT T2.Name FROM #tbl1 T2 WHERE T1.Name=T2.Name AND T1.Status=1 GROUP BY T2.Name having count(T2.Status)=1 )
Output:

basic sql - how to pivot using oracle sql

Very basic question
Right now my query is like
select table.a, table.b, table.c from table
A B C
1 2 3
.
I need my output to be
NAME ID
A 1
B 2
C 3
.
Is there a way that I can pivot my current output or query this table in a different way?
Thanks!
You need UNPIVOT:
select * from table1 unpivot (id for name in (a,b,c));
Select 'A' as name, (
select A
from table1
) as ID
union all
Select 'B', (
select B
from table1
) as ID
union all
Select 'C', (
select C
from table1
) as ID

Oracle SQL Query IN

I have following query, that's not working.
select * from table where id in (
1,2, (select id from another_table)
)
How i can rewrite it?
How about
select * from table
where id in (1,2)
or id in (select id from another_table)
Take care and use parentheses when adding additional WHERE-conditions using and!!!
select *
from table
where id in (1,2) OR id in(
select id from another_table
)
select * from table where id in (
select 1 as id from dual
union all
select 2 as id from dual
union all
select id from another_table
)
select * from table where id in (
select 1 from dual
union all
select 2 from dual
union all
select id from another_table);
I'm using union because this is faster than using an OR clause which also can be used.