Subquery based on column in main query - sql

I'm looking for help structuring a SQL query with a subquery on table2 based on a column in table1, but where table1 and table2 have no relation.
something like
SELECT name, address, dateCreated,
(SELECT itemId FROM table2 WHERE itemDate BETWEEN dateCreated AND DATEADD(ss,10,dateCreated) as item
FROM table1
So for each row 'item' must be selected from table2 based on dateCreated for that row.

You can try using IF EXISTS as shown below.
SELECT name
, [address]
, dateCreated
FROM table1
where exits(
SELECT itemId
FROM table2 WHERE itemDate BETWEEN dateCreated AND DATEADD(ss, 10,dateCreated) and table1.ItemId = table2.ItemId)

SELECT name, address, dateCreated, table2.itemId
from table1 LEFT JOIN table2 WHERE itemDate BETWEEN dateCreated AND DATEADD(ss,10,dateCreated)

If you want at most one item from table2, then your approach is fine but you want top (1):
SELECT t1.name, t1.address, t1.dateCreated,
(SELECT TOP (1) t2.itemId
FROM table2 t2
WHERE t2.itemDate BETWEEN t1.dateCreated AND DATEADD(second, 10, t1.dateCreated
) as item
FROM table1 t1;
You can also phrase this as a lateral join, using outer apply:
SELECT t1.name, t1.address, t1.dateCreated,
t2.itemId
FROM table1 t1 OUTER APPLY
(SELECT TOP (1) t2.itemId
FROM table2 t2
WHERE t2.itemDate BETWEEN t1.dateCreated AND DATEADD(second, 10, t1.dateCreated
) t2;
This makes it easy to select multiple columns.

Can you please try this below logic? The way tried, will through ERROR if there are more than one records found in table2 against any row from table1.
SELECT A.name,
A.address,
A.dateCreated,
B.itemId
FROM table1 A
INNER JOIN table2 B
ON B.itemDate BETWEEN A.dateCreated AND DATEADD(ss,10,A.dateCreated)
With the above query, you will get N numbers of row for each row in table1 based the logic applied for Date --BETWEEN A.dateCreated AND DATEADD(ss,10,A.dateCreated)

Related

How to Group By all fields nested tables in a Left Join query in BigQuery?

I have about 10 tables that I make one big nested tables by rounds with the following query:
R1 AS(
SELECT ANY_VALUE(Table1).*, ARRAY_AGG(( SELECT AS STRUCT Table2.* EXCEPT(ID))) AS Table2
FROM Table1 LEFT JOIN Table2 USING(ID)
GROUP BY Table1.ID),
R2 AS(
SELECT ANY_VALUE(R1).*, ARRAY_AGG(( SELECT AS STRUCT Table3.* EXCEPT(ID))) AS Table3
FROM R1 LEFT JOIN Table3 USING(ID)
GROUP BY R1.ID),
...
SELECT ANY_VALUE(R9).*, ARRAY_AGG(( SELECT AS STRUCT Table10.* EXCEPT(ID))) AS Table10
FROM R9 LEFT JOIN Table10 USING(ID)
The thing is that for example in my first table I can have two records with the same ID but some other fields will be different and I want to consider them as two distinct records and thus group by all the fields of the table while I join.
Then I want to do the same with all the "sub-table" (the R tables in the query), so I will able to group by all the fields of the nested tables.
How can I do it easily ?
I tried GROUP BY Table1.* but it doesn't work...
Thank you in advance
Try to_json_string:
...
FROM Table1 t1
...
GROUP BY to_json_string(t1)
You seem to want something like this:
select *
from table1 t1 left join
(select t2.*
from table2 t2
where true
qualify row_number() over (partition by t2.id order by t2.id) = 0
) t2
using (id)
This uses qualify instead of group by to fetch one row.
If you don't want all rows from from table1, you can whittle them down as well:
select *
from (select t1.*
from table1 t1
where true
qualify row_number() over (partition by id, col1, col2 order by id) = 1
) t1 left join
(select t2.*
from table2 t2
where true
qualify row_number() over (partition by t2.id order by t2.id) = 0
) t2
using (id)
How to Group By all fields ...?
I tried GROUP BY Table1.* but it doesn't work...
Consider below example
SELECT ANY_VALUE(t1).*,
ARRAY_AGG(( SELECT AS STRUCT t2.* EXCEPT(ID))) AS Table2
FROM Table1 t1 LEFT JOIN Table2 t2 USING(ID)
GROUP BY FORMAT('%t', t1)

SQL Query, how to get data from two tables

Table 1:
ID (unqiue), Name, Address
Table 2:
RecordId, ID (key of table 1), Child name
In one query, I want to retrieve all rows of Table 1 with one additional column which will be the count of all record in table 2 from ID (that is number of children for each ID in table 1). Can't figure out how to format a query to retrieve this data.
Simply Join and apply count
select T1.*, COUNT(T2.RECORDID)AS T2COUNT from Table1 T1
INNER JOIN TABLE2 T2 ON T1.ID= T2.ID
--LEFT JOIN TABLE2 T2 ON T1.ID= T2.ID --if you need 0 child records (from commets by #Cha)
GROUP BY T1.ID , T1.Name, T1.Address
The correct way of doing this will be with a OUTER JOIN:
SELECT a.ID, a.Name, a.Address, b.cnt
FROM Table1 a
LEFT OUTER JOIN
(SELECT ID, count(*) cnt from Table2 GROUP BY ID) b
ON a.ID = b.ID
The incorrect way will be with a help of a correlated sub-query:
SELECT a.ID, a.Name, a.Address,
(SELECT count(*) FROM Table2 b WHERE b.ID = a.ID) as cnt
FROM Table1 a
Here is a discussion about correlated subqueries vs OUTER JOINs, if you are interested
Group by table1 fields and count total records in table2:
here T1 alias of table1 and T2 alias of table2.
select T1.ID, T1.Name, T1.Address, count(T2.ID) as total_records
from table1 as T1
left outer join table2 as T2 on T2.ID=T1.ID
group by T1.ID, T1.Name, T1.Address

select value from another table if record is found else, use the value on current table

i'm trying to get the values from another table2 if a match exist, else, select the value in table1 but it's taking a long time to execute the query.
select table1.field1, table1.field2,
case
when exist (select top 1
from table2
where table2.field1=table1.field3
and table2.field2 is not null
order by date desc)
then (select top 1
from table2
where table2.field1=table1.field3
and table2.field2 is not null
order by date desc)
else table1.field3
end
from table1
any other way to re-write this query?
please help! n00b here :(
Yes. Use outer apply:
select t1.field1, t1.field2, coalesce(t2.??, t1.field3)
from table1 t1 outer apply
(select top 1 t2.*
from table2 t2
where t2.field1= t1.field3 and t2.field2 is not null
order by t2.date desc
) t2;
It is unclear what field you are talking about, because it is missing from the question; hence, the ??.
SELECT t1.field1, t1.field2, coalesce(t2.field2,t1.field3) as field3
FROM table1 t1
LEFT JOIN table2 t2
on t2.field1=t1.field3
and t2.date = (select max(date) from table2 t2e where t2.field1=t2e.field2)
SELECT
table1.field1,
table1.field2,
COALESCE(table2.field2,table1.field3)
FROM
table1
LEFT OUTER JOIN
table2
ON
table2.field1=table1.field3
COALESCE skips all the null values in the list.
LEFT OUTER JOIN returns all values from the first table, but puts null values where there is no corresponding row in the second table.

Select from table not in another table

I have two tables, each with the following fields: IDnumber, SectionNumber, Date. There is overlapping information in the two tables.
How do I select only rows that do NOT overlap (ie. in one table but not the other)?
You can use a NOT IN in your WHERE clause.
SELECT IDnumber, SectionNumber, Date
FROM table1
WHERE IDnumber NOT IN (SELECT IDnumber FROM table2)
OR NOT EXISTS
SELECT IDnumber, SectionNumber, Date
FROM table1 t1
WHERE NOT EXISTS (SELECT IDnumber FROM table2 t2 WHERE t1.IDnumber = t2.IDnumber)
Which DBMS?
If SQL Server, then it's almost what you wrote in the title...
SELECT *
FROM Table1
WHERE IDnumber NOT IN (SELECT IDnumber FROM Table2)
If you want to compare multiple columns, you need an outer join:
select table1.*
from table1 left outer join
table2
on table1.id = table2.id and
table1.SectionNumber = table2.SectionNumber and
table1.date = table2.date
where table2.id is null
In the case where you might have many matches between the tables, then the join can be inefficient. Assuming you only want those three fields, you can use a trick that avoids the join:
select id, SectionNumber, date
from ((select 0 as IsTable2, id, SectionNumber, date
from table1
) union all
(select 1 as IsTable2, id, SectionNumber, date
from table2
)
) t
group by id, SectionNumber, date
having max(isTable2) = 0
SELECT *
FROM Table1 t1 left join Table2 t2
on t1.id=t2.id
where t2.id is null

SQL Query with conditional JOIN

The scenario:
Table1
CatId|Name|Description
Table2
ItId|Title|Date|CatId (foreign key)
I want to return all rows from Table1 and Title,Date from Table2, where
The returned from Table 2 must be the Latest one by the date column.
(in second table there many items with same CatId and I need just the latest)
I have 2 queries but can't merge them together:
Query 1:
SELECT Table1.Name, Table1.Description,
Table2.Title, Table2.Date
FROM
Table1 LEFT JOIN Table2 ON Table1.CatId=Table2.CatId
Query2:
SELECT TOP 1 Table2.Title, Table2.Date
FROM
Table2
WHERE
Table2.CatId = #inputParam
ORDER BY Table2.Date DESC
You can use a UNION, but you'll need to make the columns match up:
OK, after rereading the question, I understand what you're trying to do.
This should do the trick:
SELECT Table1.Name, Table1.Description,
T2.Title, T2.Date
FROM
Table1
LEFT JOIN (
SELECT CatId, Title, Date, ROW_NUMBER() over (ORDER BY CatId, Date DESC) - RANK() over (ORDER BY CatID) as Num
FROM Table2) T2 on T2.CatId = Table1.CatId AND T2.Num = 0
Sounds like you're talking about a groupwise maximum (newest row in Table2 for each matching row in Table1), in which case, the easiest way is use ROW_NUMBER:
WITH CTE AS
(
SELECT
t1.Name, t1.Description, t2.Title, t2.Date,
ROW_NUMBER() OVER (PARTITION BY t1.CatId ORDER BY t2.Date DESC) AS Seq
FROM Table1 t1
LEFT JOIN Table2 t2
ON t2.CatId = t1.CatId
)
SELECT *
FROM CTE
WHERE Seq = 1
OR Date IS NULL
Shouldn't this work?
SELECT Table1.Name, Table1.Description,
T2.Title, T2.Date
FROM
Table1 LEFT JOIN (
SELECT TOP 1 Table2.CatId Table2.Title, Table2.Date
FROM
Table2
WHERE
Table2.CatId = Table1.catId
ORDER BY Table2.Date DESC
) T2
ON Table1.CatId=T2.CatId