Google BigQuery: Table join with REPEATED RECORD values - arrays

I have a table like this:
Row field1 field2 field3.a field3.b
1 value1 1 id1 key5
id2 key6
2 value2 2 id3 key7
id4 key8
The first 2 columns are standard fields, the third column is a REPEATED RECORD field.
I have 2 additional tables
Row id value
1 id1 my-valueA
2 id2 my-valueB
3 id3 my-valueC
4 id4 my-valueD
and
Row id value
1 key5 my-valueE
2 key6 my-valueF
3 key7 my-valueG
4 key8 my-valueH
Which map the a id/key from the first table (I used the term key and id to avoid confusion, but at the end the concept is the same) with a given value
Here is a full statement to reproduce the structure
#standardSQL
WITH my_table AS (
SELECT "value1" as field1, 1 as field2, [STRUCT("id1" as a, "key5" as b),STRUCT("id2" as a, "key6" as b)] as field3
UNION ALL
SELECT "value2" as field2, 2 as field2, [STRUCT("id3" as a, "key7" as b),STRUCT("id4" as a, "key8" as b)] as field3
),
ids_table AS (
SELECT "id1" as id, "my-valueA" as value
UNION ALL
SELECT "id2" as id, "my-valueB" as value
UNION ALL
SELECT "id3" as id, "my-valueC" as value
UNION ALL
SELECT "id4" as id, "my-valueD" as value
),
keys_table AS (
SELECT "key5" as id, "my-valueE" as value
UNION ALL
SELECT "key6" as id, "my-valueF" as value
UNION ALL
SELECT "key7" as id, "my-valueG" as value
UNION ALL
SELECT "key8" as id, "my-valueH" as value
)
-- SELECT * FROM my_table
-- SELECT * FROM ids_table
-- SELECT * FROM keys_table
My goal is to replace the key/id values from the first tables with the value given by the 2 other tables, like a classic join on id.
Here is the expected output
Row field1 field2 t2_value t3_value
1 value1 1 my-valueA my-valueE
my-valueB my-valueF
2 value2 2 my-valueC my-valueG
my-valueD my-valueH
At first I thought about using UNNEST operator to obtain flat lines, so a simple JOIN can be made to resolve the value and after that rejoin the array with the replaced values.
SELECT my_table.* EXCEPT(field3),
t2.value as t2_value,
t3.value as t3_value
FROM my_table CROSS JOIN UNNEST(my_table.field3) AS t1
LEFT JOIN ids_table AS t2 ON t1.a = t2.id
LEFT JOIN keys_table as t3 ON t1.b = t3.id
With this statement the values are properly replace from the id to the value, but now I'm unable to reproduce the RECORD REPEATED structure of before

Below is for BigQuery Standard SQL
#standardSQL
WITH my_table AS (
SELECT "value1" AS field1, 1 AS field2, [STRUCT("id1" AS a, "key5" AS b),STRUCT("id2" AS a, "key6" AS b)] AS field3 UNION ALL
SELECT "value2" AS field2, 2 AS field2, [STRUCT("id3" AS a, "key7" AS b),STRUCT("id4" AS a, "key8" AS b)] AS field3
), ids_table AS (
SELECT "id1" AS id, "my-valueA" AS value UNION ALL
SELECT "id2" AS id, "my-valueB" AS value UNION ALL
SELECT "id3" AS id, "my-valueC" AS value UNION ALL
SELECT "id4" AS id, "my-valueD" AS value
),keys_table AS (
SELECT "key5" AS id, "my-valueE" AS value UNION ALL
SELECT "key6" AS id, "my-valueF" AS value UNION ALL
SELECT "key7" AS id, "my-valueG" AS value UNION ALL
SELECT "key8" AS id, "my-valueH" AS value
)
SELECT
field1, field2,
(
SELECT ARRAY_AGG(STRUCT<a_value STRING, b_value STRING>(t2.value, t3.value))
FROM UNNEST(field3) t1
LEFT JOIN ids_table AS t2 ON t1.a = t2.id
LEFT JOIN keys_table AS t3 ON t1.b = t3.id
) AS field3
FROM my_table
with below output
field1 field2 field3.a_value field3.b_value
value1 1 my-valueA my-valueE
my-valueB my-valueF
value2 2 my-valueC my-valueG
my-valueD my-valueH

Related

How to Join Array of struct on table1 with normal column of table 2 in BigQuery

Tabel1 and Table 2
select p.id,q.description
from table1 p
join table2 q
on q.control_number
in unnest(p.results.control_number)
When I process this I'm getting the below error:
Cannot access field control_number on a value with type
ARRAY<STRUCT<control_number string,...., …>>
I have also tried un-nesting after the table like:
select p.id,q.f.description
from table1 p,Unnest(finder) f
join table2 q
on q.control_number in unnest(p.f.results.control_number)
But this also did not work.
Can anyone tell me what's wrong?
Another option
select p.id,q.description
from table1 p, table2 q
where q.control_number in (select control_number from p.finder)
Try the following in standard SQL:
with table1 as (
select '1' id, array[struct('a1' as control_number)] finder
UNION ALL
select '2' id, array[struct('a2' as control_number)] finder
UNION ALL
select '3' id, array[struct('a3' as control_number)] finder
),
table2 as (
select 'description for a1' description, 'a1' control_number
UNION ALL
select 'description for a2' description, 'a2' control_number
)
select p.id,q.description
from table1 p, unnest(p.finder) f join table2 q on q.control_number = f.control_number;
WITH clause is used to simulate data in your tables.

Single query to return one to many by a search on the many

I've got a table like this
Table1Id | Column2
-------------------
100 | somedata
And one like this
Table2Id|Table1Id|Name |Value
-------------------------------
500 |100 |name1 |value1
501 |100 |name2 |value2
I have "name1" and "value1" to search with and I want to retrieve everything from table1 with it. That's easy but how to retrieve the rest of the children in table2 when I've only got the data from the first row? I want to do it in a single query and I wanted to avoid subqueries but not sure if that's possible.
Can someone fix this query to return the other child row in table2?
SELECT *
FROM Table1 t1
JOIN table2 t2 on t1.Table1Id = t2.Table1Id
WHERE t2.Name = 'name1' AND t2.Value = 'value1'
select T1.*, T2.*
FROM Table1 T1
INNER JOIN Table2 T2 on T1.Table1Id = T2.Table1Id
INNER JOIN Table2 Query on T1.id= Query.Table1Id
WHERE Query.[Name] = 'name1' AND Query.[Value] = 'value1'
Note that this will not throw an error if there are more than 1 Table2 rows with the same combination of Name and Value.
Unsure why you want to avoid sub-queries in this instance a sub-query provides the best performance e.g.
declare #Table1 table (Table1Id int, Column2 varchar(32));
declare #Table2 table (Table2Id int, Table1Id int, [Name] varchar(32), [Value] varchar(32));
insert into #Table1 (Table1Id, Column2)
select 100, 'somevalue1' union all
select 101, 'somevalue2'
insert into #Table2 (Table2Id, Table1Id, [Name], [Value])
select 500, 100, 'name1', 'value1' union all
select 501, 100, 'name2', 'value2' union all
select 502, 101, 'name3', 'value3' union all
select 503, 101, 'name4', 'value4'
SELECT *
FROM #Table1 T1
INNER JOIN #Table2 T2 on T1.Table1Id = T2.Table1Id
WHERE T1.Table1Id = (
SELECT T2A.Table1Id
FROM #Table2 T2A
WHERE T2A.[Name] = 'name1' AND T2A.[Value] = 'value1'
)
Gives:
Table1Id Column2 Table2Id Table1Id Name Value
100 somevalue1 500 100 name1 value1
100 somevalue1 501 100 name2 value2
Maybe this is what you are looking for, not at all sure:
select *
from Table2 t2
left join Table1 t1 on t1.Table1Id = t2.Table1Id
and t2.Name = 'name1' and t2.Value = 'value1'

Join two tables and combine the same fields using another field in one table and remaining fields as it is

I have two tables (table1 and table2), both have one column in common (field1). I need to join both tables. Then name the field1 contents with a another column contents (field2)in table1 and remaining table2 contents as it is.
Table1:
Field1 Field2
------------------
cat pet1
dog pet2
camel pet3
Table2:
field1
--------
cat
dog
camel
lion
tiger
wolf
My output should be
Field1
------------
pet1
pet2
pet3
lion
tiger
wolf
Check this -
Select field2 from table1 where field1
In (select field1 from table2)
Union
Select field1 from table1 where
Field1 not in (select field1 from table2)
Union
Select field1 from table2 where
Field1 not in (select field1 from table1);
SQL Fiddle
Just use Temp table variable to store join query result & interchange the temp table data with field1 as below :
insert into temp
select t2.field1, t1.field2 from
(
select * from table2
)t2
left join table1 t1 on t1.field1 = t2.field1
update temp set field1 = filed
where field1 in ('cat', 'dog', 'camel')
select field1 from temp
Description is unclear, but I suppose it is so.
SELECT T2.Field1 as Data
FROM Table2 as T2
LEFT OUTER JOIN Table1 as T1
ON T1.Field1 = T2.Field2
WHERE T1.Field1 IS NULL
UNION ALL
SELECT Field2 as Data
FROM Table1;

How to join two Tables which have no unique ID

I am trying to Left join Table 1 to table 2
Table1 Table2
ID Data ID Data2
1 r 1 q
2 t 1 a
3 z 2 x
1 u 3 c
After i have left joined this two Tables i would like get something like this
Table1+2
ID Data Data2
1 r a
2 t x
3 z c
1 u q
and NOT
Table1+2
ID Data Data2
1 r q
2 t x
3 z c
1 u q
and my question is: is there any possibility to tell table 2 that if u have used something for table 1, dont use it and give me next value. do i have to make it im T-SQL or to and new column where i can list if this id exists then write 2 if not 1(Number data). How can i solve this problem?
Ty u in advance.
Since there's no uniqueness in the ID on both tables, lets add some uniqueness to it.
So it can be used to join on.
The window function ROW_NUMBER can be used for that.
An example solution that gives the expected result:
DECLARE #TestTable1 TABLE (ID INT, Data VARCHAR(1));
DECLARE #TestTable2 TABLE (ID INT, Data VARCHAR(1));
INSERT INTO #TestTable1 VALUES (1,'r'),(2,'t'),(3,'z'),(1,'u');
INSERT INTO #TestTable2 VALUES (1,'q'),(1,'a'),(2,'x'),(3,'c');
select
t1.ID, t1.Data,
t2.Data as Data2
from (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable1
) t1
left join (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable2
) t2 on t1.ID = t2.ID and t1.rn = t2.rn;
Note: Because of the LEFT JOIN, this does assume the amount of same ID's in table2 are equal or lower can those on table1. But you can change that to a FULL JOIN if that's not the case.
Returns :
ID Data Data2
1 r a
1 u q
2 t x
3 z c
To get the other result could have been achieved in different ways.
This is actually a more common situation.
Where one wants all from Table 1, but only get one value from Table 2 for each record of Table 1.
1) A top 1 with ties in combination with a order by rownumber()
select top 1 with ties
t1.ID, t1.Data,
t2.Data as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
order by row_number() over (partition by t1.ID, t1.Data order by t2.Data desc);
The top 1 with ties will only show those where the row_number() = 1
2) Using the row_number in a subquery:
select ID, Data, Data2
from (
select
t1.ID, t1.Data,
t2.Data as Data2,
row_number() over (partition by t1.ID, t1.Data order by t2.Data desc) as rn
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
) q
where rn = 1;
3) just a simple group by and a max :
select t1.ID, t1.Data, max(t2.Data) as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
group by t1.ID, t1.Data
order by 1,2;
All 3 give the same result:
ID Data Data2
1 r q
1 u q
2 t x
3 z c
Use ROW_NUMBER
DECLARE #Table1 TABLE (ID INT, DATA VARCHAR(10))
DECLARE #Table2 TABLE (ID INT, DATA VARCHAR(10))
INSERT INTO #Table1
VALUES
(1, 'r'),
(2, 't'),
(3, 'z'),
(1, 'u')
INSERT INTO #Table2
VALUES
(1, 'q'),
(1, 'a'),
(2, 'x'),
(3, 'c')
SELECT
A.*,
B.DATA
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table1) A INNER JOIN
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table2) B ON A.ID = B.ID AND
A.RowId = B.RowId

SQL query for displaying count if same name comes in adjacent row it should show the count else 1

I have a table tb1 with columns id,name,
if same name comes in adjacent row it should display the count count else 1
For eg:
id name
1 sam
2 jose
3 sam
4 sam
5 dev
6 jose
Result want to be
name counts
sam 1
jose 1
sam 2
dev 1
jose 1
please help.
Check out this one :(SELF JOIN)
create table #sampele(id int,name varchar(50))
insert into #sampele values(1,'sam')
insert into #sampele values(2,'jose')
insert into #sampele values(3,'sam')
insert into #sampele values(4,'sam')
insert into #sampele values(5,'dev')
insert into #sampele values(6,'jose')
select a.id,a.name,case when a.name = b.name then 2 else 1 end as cnt from
#sampele a
left outer join
#sampele b
on a.id = b.id+1
Try a combination with a sub query, "COUNT(*) OVER (PARTITION", and row_number():
--DROP TABLE #Test;
SELECT id = IDENTITY(INT,1,1), name INTO #Test FROM
(
SELECT name = 'sam' UNION ALL
SELECT 'jose' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'dev ' UNION ALL
SELECT 'dev ' UNION ALL
SELECT 'jose' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'jose'
) a;
GO
WITH GetEndID AS (
SELECT *
, EndID =(SELECT MIN(id) FROM #Test b WHERE b.name != a.name AND b.id > a.id)
FROM #Test a
), GetCount AS
(
SELECT
*
, NameCount = COUNT(*) OVER (PARTITION BY EndID)
, OrderPrio = ROW_NUMBER() OVER (PARTITION BY EndID ORDER BY id)
FROM GetEndID
)
SELECT id, name, NameCount FROM GetCount WHERE OrderPrio = 1 ORDER BY id;
select distinct a.name,case when a.name = b.name then 2 else 1 end as cnt from
tb1 a
left outer join
tb1 b
on a.id = b.id+1
sQlfiddle
Click to see running

Resources