I have a query that produces two separate IDs:
SELECT
date,
user_id,
vendor_id,
SUM(purchase) user_purchase
SUM(spend) vendor_spend
GROUP BY 1,2,3
FROM tabla.abc
This produces results like this:
date user_id vendor_id user_purchase vendor_spend
1/1/18 123 NULL 5.00 0.00
1/1/18 NULL 456 0.00 10.00
I want to join it on a table that looks like this:
client_id user_id vendor_id
456789 123 NULL
101112 NULL 456
But the problem is, I obviously want to join it on both the appropiate IDs so my final output can look like this:
date client_id user_id vendor_id user_purchase vendor_spend
1/1/18 456790 123 NULL 5.00 0.00
1/1/18 101112 NULL 456 0.00 10.00
So is there a way I can do like, a conditional join? Something like WHERE user_id IS NULL THEN... etc...
Use not distinct from because one of the argument may be null:
select *
from (
select
date,
user_id,
vendor_id,
sum(purchase) user_purchase,
sum(spend) vendor_spend
from table1
group by 1,2,3
) t1
join table2 t2
on (t1.user_id, t1.vendor_id)
is not distinct from (t2.user_id, t2.vendor_id)
Note that for performance reasons you should join already aggregated table (hence I have placed the original query in a derived table).
Try this:
SELECT
date,
COALESCE(lu.client_id, lv.client_id) AS client_id,
user_id,
vendor_id,
SUM(purchase) user_purchase
SUM(spend) vendor_spend
FROM tabla.abc
LEFT JOIN tabla.link AS lu USING (user_id)
LEFT JOIN tabla.link AS lv USING (vendor_id)
GROUP BY 1,2,3,4
I think the sufficient join is just this:
FROM aggregated_table t1
LEFT JOIN client_id_table t2
ON t1.user_id=t2.user_id
OR t1.vendor_id=t2.vendor_id
because as I understand you need to join by user id if there is user id and by vendor id if there is vendor id. Using a left join with OR does exactly that.
Also, conditional join is possible as well. If you're familiar with a CASE statement it works perfectly well in join conditions. Similar thing can be expressed as:
FROM aggregated_table t1
LEFT JOIN client_id_table t2
ON CASE
WHEN t1.user_id is not null THEN t1.user_id=t2.user_id
WHEN t1.vendor_id is not null THEN t1.vendor_id=t2.vendor_id
END
but this is too verbose compared to the previous option that I think should produce the same result
Related
how to find number of records in both table using join.
i have two tables table1 and table2 with same structure.
table1
id
item
1
A
1
B
1
C
2
A
2
B
table2
id
item
1
A
1
B
2
A
2
B
2
C
2
D
Output should be like this.
id
table1.itemcount
table2.itemcount
1
3
2
2
2
4
SELECT DISTINCT id, (
SELECT COUNT(*) FROM table1 AS table1_2 WHERE table1_2.id=table1.id
) AS "table1.itemcount", (
SELECT COUNT(*) FROM table2 AS table2_2 WHERE table2_2.id=table1.id
) AS "table2.itemcount"
FROM table1;
Assuming that each id is guaranteed to exist in both tables, the following would work
select
t1.id,
count(distinct t1.item) t1count,
count(distinct t2.item) t2count
from t1
join t2 on t1.id = t2.id
group by 1;
But if that is not guaranteed then we'll have to use full outer join to get unique ids from both tables
select
coalesce(t1.id, t2.id) id,
count(distinct t1.item) t1count,
count(distinct t2.item) t2count
from t1
full outer join t2 on t1.id = t2.id
group by 1;
We're using coalesce here as well for id because if it only exists in t2, t1.id would result in null.
#DeeStark's answer also works if ids are guaranteed to be in both tables but it's quite inefficient because count is essentially run twice for every distinct id in the table. Here's the fiddle where you can test out different approaches. I've prefixed each query with explain which shows the cost
Hope this helps
I have a difficulty dealing with a SQL query. I use PostgreSQL.
The query says: Show the customers that have done at least an order that contains products from 3 different categories. The result will be 2 columns, CustomerID, and the amount of orders. I have written this code but I don't think it's correct.
select SalesOrderHeader.CustomerID,
count(SalesOrderHeader.SalesOrderID) AS amount_of_orders
from SalesOrderHeader
inner join SalesOrderDetail on
(SalesOrderHeader.SalesOrderID=SalesOrderDetail.SalesOrderID)
inner join Product on
(SalesOrderDetail.ProductID=Product.ProductID)
where SalesOrderDetail.SalesOrderDetailID in
(select DISTINCT count(ProductCategoryID)
from Product
group by ProductCategoryID
having count(DISTINCT ProductCategoryID)>=3)
group by SalesOrderHeader.CustomerID;
Here are the database tables needed for the query:
where SalesOrderDetail.SalesOrderDetailID in
(select DISTINCT count(ProductCategoryID)
Is never going to give you a result as an ID (SalesOrderDetailID) will never logically match a COUNT (count(ProductCategoryID)).
This should get you the output I think you want.
SELECT soh.CustomerID, COUNT(soh.SalesOrderID) AS amount_of_orders
FROM SalesOrderHeader soh
INNER JOIN SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
INNER JOIN Product p ON sod.ProductID = p.ProductID
HAVING COUNT(DISTINCT p.ProductCategoryID) >= 3
GROUP BY soh.CustomerID
Try this :
select CustomerID,count(*) as amount_of_order from
SalesOrder join
(
select SalesOrderID,count(distinct ProductCategoryID) CategoryCount
from SalesOrderDetail JOIN Product using (ProductId)
group by 1
) CatCount using (SalesOrderId)
group by 1
having bool_or(CategoryCount>=3) -- At least on CategoryCount>=3
I have an existing table1 which contains "account", "tax_year" and other fields. I want to create a table2 with records from table1 when the frequency of CONCAT(account, tax_year) is 1 and meet the WHERE clause.
For instance, if table1 looks like below:
account year
aaa 2014
bbb 2016
bbb 2016
ddd 2014
ddd 2014
ddd 2015
Table2 should be:
account year
aaa 2014
ddd 2015
Here is my script:
DROP TABLE IF EXISTS table1;
CREATE table2 AS
SELECT
account::text,
tax_year::text,
building_number,
imprv_type,
building_style_code,
quality,
quality_description,
date_erected,
yr_remodel,
actual_area,
heat_area,
gross_area,
CONCAT(account, tax_year) AS unq
FROM table1
WHERE imprv_type=1001 and date_erected>0 and date_erected IS NOT NULL and quality IS NOT NULL and quality_description IS NOT NULL and yr_remodel>0 and yr_remodel IS NOT NULL and heat_area>0 and heat_area IS NOT NULL
GROUP BY account,
tax_year,
building_number,
imprv_type,
building_style_code,
quality,
quality_description,
date_erected,
yr_remodel,
actual_area,
heat_area,
gross_area,
unq
HAVING COUNT(unq)=1;
I've spent two days on it but still can't figure out how to make it right. Thank you ahead for your help!
The proper way to use count of pairs (account, tax_year) in table1:
select account, tax_year
from table1
where imprv_type=1001 -- and many more...
group by account, tax_year
having count(*) = 1;
so you should try:
create table table2 as
select *
from table1
where (account, tax_year) in (
select account, tax_year
from table1
where imprv_type=1001 -- and many more...
group by account, tax_year
having count(*) = 1
);
COUNT() = 1 is equivalent to NOT EXISTS(another with the same key fields):
SELECT
account, tax_year
-- ... maybe more fields ...
FROM table1 t1
WHERE NOT EXISTS ( SELECT *
FROM table1 nx
WHERE nx.account = t1.account -- same key field(s)
AND nx.tax_year = t1.tax_year
AND nx.ctid <> t1.ctid -- but a different row!
);
Note: I replaced the COUNT(CONCAT(account, tax_year) concatenation of key fields by a composite match key.
Sorry about the lame Title... If I could summarize this in a few words I might have had better luck finding an existing solution here!
I have a table that simplified looks like this:
ID PRODUCT
___ _________
100 Savings
200 Mortgage
200 Visa
300 Mortgage
300 Savings
I need to select rows based on the product of each ID. For example, I can do this:
SELECT DISTINCT ID
FROM table1
WHERE Product NOT IN ('Savings', 'Chequing')
This would return:
ID
___
200
300
However, in the case of ID 300 they do have Savings so I actually do not want this returned. In plain English I want to
Select * from table1 where 'Savings' and 'Chequing' are not the product for any row with that ID.
Desired result in this case would be one row with ID 200 since they do not have Savings or Chequing.
How can I do this?
Select the rows that match the item you do not want to match then compare therr ids
e.g.
select distinct id from table1 where id not in (
SELECT ID
FROM table1
WHERE Product IN ('Savings', 'Chequing')
)
You can use NOT EXISTS:
SELECT DISTINCT t1.ID
FROM dbo.Table1 t1
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.Table1 t2
WHERE t2.Poduct IN ('Savings', 'Chequing')
AND t2.ID = t1.ID
)
Demo
Worth reading: Should I use NOT IN, OUTER APPLY, LEFT OUTER JOIN, EXCEPT, or NOT EXISTS?
Alright let me explain my question with example
We have a table that contains
Id
Name
Number
Now example
1 House 4
2 Hospital 3
3 Airport 'null'
4 Station 2
select t1.id,
t1.name,
t2.name as name2
from your_table t1
left join your_table t2 on t1.number = t2.id
Ok when querying as the above, that 'null' value containing column is giving error. So i want to modify above query in a way that it will return name2 as null and won't give error for that rows.
So the result I expect should be:
1 House Station
2 Hospital Airport
3 Airport null
4 Station Hospital
This null here is as string.
The current error I get
Msg 245, Level 16, State 1, Line 5
Conversion failed when converting the varchar value 'null' to data type smallint.
thank you
You should fix your database design. Meantime, use NULLIF to get your expected results:
select t1.id,
t1.name,
t2.name as name2
from your_table t1
left join your_table t2 on NULLIF( t1.number, 'NULL' ) = t2.id