SQL query to fetch data based on column value - sql

Is it possible to get entire data in one attempt for this scenario? I have this query where I need retrieve product name from another table.
SELECT T1.CASE_ID,
T2.PRODUCT_ID,
T2.LEVEL,
(CASE WHEN T2.LEVEL = 3 THEN T3.PARENT_PRODUCT_ID
WHEN T2.LEVEL = 2 THEN T2.PRODUCT_ID
WHEN T2.LEVEL = 1 THEN NULL END) AS NEW_PRODUCT_ID,
T3.PRODUCT_NAME
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.CASE_ID = T2.CASE_ID
LEFT OUTER JOIN TABLE3 T3
ON T2.PRODUCT_ID=T3.PRODUCT_ID
Right now the T3.PRODUCT_NAME return value based on T2.PRODUCT_ID but what I really need is to able to retrieve data based on the value from NEW_PRODUCT_ID?
Here is my expected output:
Hope this makes sense.

You can use a subquery
SELECT T4.CASE_ID, T4.PRODUCT_ID, T4.LEVEL, T4.NEW_PRODUCT_ID, T5.PRODUCT_NAME
FROM (
SELECT T1.CASE_ID,
T2.PRODUCT_ID,
T2.LEVEL,
(CASE WHEN T2.LEVEL = 3 THEN T3.PARENT_PRODUCT_ID
WHEN T2.LEVEL = 2 THEN T2.PRODUCT_ID
WHEN T2.LEVEL = 1 THEN NULL END) AS NEW_PRODUCT_ID,
T3.PRODUCT_NAME
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.CASE_ID = T2.CASE_ID
LEFT OUTER JOIN TABLE3 T3
ON T2.PRODUCT_ID=T3.PRODUCT_ID
) AS T4
LEFT OUTER JOIN TABLE3 T5
ON T4.NEW_PRODUCT_ID=T5.PRODUCT_ID

Related

SQL Multiple subquery issue

Currently struggling with a second subquery (t3) which is giving me a syntax error. The query works fine if t3 is excluded.
SELECT switch(LEFT(t1.[treatment],1)='C',"Complaint",LEFT(t1.[treatment],1)='P',"Post") AS Treatment, count(t1.[ID]) AS Total_Vol, count(t2.[event]) AS Total_Posted, format(count(t2.[event]) / count(t1.[ID]),"0.00%") AS Percentage, COUNT(IIF(t1.[requirements]='1',1,)) AS Special _Population,count(t3.[approved]) as Approved_vol
FROM Main_audit_table_v3 AS t1 LEFT JOIN (SELECT t2.[ID], t2.[event] FROM Main _table AS t2 WHERE t2.event Not Like ('NA')) AS t2 ON t1.[ID] = t2.[ID]
LEFT JOIN (SELECT t3.[ref],t3.[requirement],t3.[approved] from Main_table AS t3 where
t3.[requirement] = '1' and t3.[approved] not like ('NA')) as t3
t2.[ID] = t3.[ID]
GROUP BY LEFT(t1.[treatment],1);
The expected output is that the [approved] column will provide a count of records where requirement = 1 and approved not like NA.
In MS Access you need additional parentheses for JOINs. And you are missing ON:
SELECT . . .
FROM (Main_audit_table_v3 AS t1 LEFT JOIN
(SELECT t2.[ID], t2.[event]
FROM Main _table AS t2
WHERE t2.event Not Like ('NA')
) AS t2 ON t1.[ID] = t2.[ID]
) LEFT JOIN
(SELECT t3.[ref], t3.[requirement], t3.[approved]
FROM Main_table AS t3
WHERE t3.[requirement] = '1' and t3.[approved] not like 'NA'
) as t3
ON t2.[ID] = t3.[ID]
GROUP BY LEFT(t1.[treatment], 1);

Sum on Multiple Left Joins

I am trying to sum the total value of a column for a specific ID after multiple left joins.
The below code gives me what I am looking for but across multiple rows, I need the value for T3.C_Amt and T4.E_Amt to be totaled.
SELECT
T1.ID,
T2.Unique_ID,
T3.C_Date,
T3.C_Amount,
T4.D_Date,
T4.D_Amount
FROM
TABLE_1 T1
LEFT JOIN DATABASE1.TABLE_2 T2
ON T1.ID = T2.UNIQUE_ID
LEFT JOIN DATABASE1.TABLE_3 T3
ON T2.Unique_ID = T3.Unique_ID
AND T3.C_Date = '2019-04-11'
LEFT JOIN DATABASE1.TABLE_4 T4
ON T2.Unique_ID = T4.Unique_ID
AND T4.D_Date= '2019-04-11'
--this needs to be summed to have the total amount
I want it to return one row for the Unique ID with total C_Amount and total D_Amount for the specific date
Use aggregation with group by
SELECT T2.Unique_ID,T3.C_Date,sum(T3.C_Amount),
T4.D_Date,sum(T4.D_Amount)
FROM TABLE_1 T1
LEFT JOIN DATABASE1.TABLE_2 T2
ON T1.ID = T2.UNIQUE_ID
LEFT JOIN DATABASE1.TABLE_3 T3
ON T2.Unique_ID = T3.Unique_ID AND T3.C_Date = '2019-04-11'
LEFT JOIN DATABASE1.TABLE_4 T4
ON T2.Unique_ID = T4.Unique_ID AND T4.D_Date= '2019-04-11'
group by T2.Unique_ID,T3.C_Date,T4.D_Date
I would do it this way. Since Teradata is a MPP, there should not be much of a performance impact as well.
SELECT Unique_ID,C_Date,sum(C_Amount),D_Date,sum(D_Amount)
FROM
(
SELECT
T1.ID ID,
T2.Unique_ID Unique_ID,
T3.C_Date C_Date,
T3.C_Amount C_Amount,
T4.D_Date D_Date,
T4.D_Amount D_Amount
FROM
TABLE_1 T1
LEFT JOIN DATABASE1.TABLE_2 T2
ON T1.ID = T2.UNIQUE_ID
LEFT JOIN DATABASE1.TABLE_3 T3
ON T2.Unique_ID = T3.Unique_ID
AND T3.C_Date = '2019-04-11'
LEFT JOIN DATABASE1.TABLE_4 T4
ON T2.Unique_ID = T4.Unique_ID
AND T4.D_Date= '2019-04-11'
) ABC
GROUP BY Unique_ID,C_Date,D_Date
I would add a concern of 1-to-many causing a false total. What if table 3 has 10 records for a given T2.UniqueID and another 5 for the T4 table. You have just compounded your total completely out of range.
As such, I would pre-aggregate from the child tables grouped by the unique ID filtered on the date. Also, you can remove the T2 table due to associative properties.
T1.ID = T2.Unique_ID = T3.Unique_ID = T4.Unique_ID
to T1.ID = T3.Unique_ID = T4.Unique_ID
SELECT
T1.ID,
T3.C_Date,
T3.C_Amount,
T4.D_Date,
T4.D_Amount
FROM
TABLE_1 T1
LEFT JOIN
( Select Unique_ID, sum( C_Amount ) as T3Sum
from DATABASE1.TABLE_3
where T3.C_Date = '2019-04-11'
group by Unique_ID ) T3
ON T1.ID = T3.Unique_ID
LEFT JOIN
( select Unique_ID, sum( D_Amount ) T4Sum
from DATABASE1.TABLE_4
where D_Date= '2019-04-11'
group by Unique_ID ) T4
ON T1.ID = T4.Unique_ID
Now, your ambiguity on table names might help being more real-life descriptive. Your summary amounts are based on a single date, but how many records in T1 that are applicable? If you have 5k rows in T1 and only 450 entries total between tables T3 and T4, your result set would still give you all the rows. That being said, you probably dont want the bloat of records that don't have any such details in the secondary sum subqueries. I would add a WHERE clause at the end
WHERE
T3.Unique_ID IS NOT NULL
OR T4.Unique_ID IS NOT NULL

Joining tbl1 to select statement twice with join to tbl2 that also joins to tbl3

I'm using SQL server manger.
I have 3 tables
I need a query that pulls t1 ands add an Origin Basin and a Destination Basin.
So far I have the following:
select T1.[Country (destination)], T3.AreaName
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
inner join T3 on
T2.AreaID = T3.AreaID
Which returns:
Country | Area
However, I'm having trouble doing this for the second country column. I believe you use aliases. I've tried:
select (select AreaName
FROM T3
where T3.AreaID = T2.AreaID) as 'Area Imp',
(select AreaID
From T2
where T2.CountryName = T1.[Country (origin)]) as 'x',
(select AreaID
From T2
where T2.CountryName = T1.[Country (destination)]) as 'y'
FROM T1
But I can't get it to work.
This is what you need to do:
select t1.date, t1.country_destination, t1.country_origin, destination_area.AreaName as area_destination, origin_area.AreaName as area_origin
from t1 as t1 join t2 as destination on t1.country_destination = destination.countryname
join t2 as origin on t1.country_origin = origin.countryname
join t3 as destination_area on t2.areaid = destination_area.areaid
join t3 as origin_area on t2.areaid = origin_area.areaid
You will need to join with the same table twice, both for t2 and t3 so that you get the matching records for your needs.
It helps usually to put aliases that match the purpose of the join (in this case, destination and origin) when writing the query.
I think what you're trying to do is something like this:
select T1.*, T3dest.AreaName, T3orig.AreaName
From
T1
inner join
T2 T2dest on
T1.[Country (destination)] = T2dest.CountryName
inner join
T3 T3dest on
T2dest.AreaID = T3dest.AreaID
inner join
T2 T2orig on
T1.[Country (origin)] = T2orig.CountryName
inner join
T3 T3orig on
T2orig.AreaID = T3orig.AreaID
Note that I've switched to inner joins throughout, at the moment. If you do want left join semantics, you either need to use those for all of the joins to the T2 and T3 tables or you need to change the join order (so that the relevant T3 joins to the T2 tables occur before the attempted join with T1). It's not clear from the sample data if that's required, however.
Try this, You would still want to join on area id's
select T1.Date,T1.[Country (destination)], null [Country (origin)], T3.AreaName [AreaName(Destination)], null [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
union all
select T1.Date,null [Country (destination)], t1.[Country (origin)], Null [AreaName(Destination)], t3. [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (Origin)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID

If exists sql error combine 2 select statement

When a subquery is not introduced with EXISTS, only one expression can be specified in the selection list.error. Not sure how to do the if exist statement.
SELECT DISTINCT
t1.id,t1.scn,t1.vsl_name,case when t1.id = t1.id THEN 'IMPORT' ELSE '0' END AS import_export,
dbo.fn_format_datetime(t1.act_arr_dt_tm) AS act_arr_dt_tm,
dbo.fn_format_datetime(t1.act_dept_dt_tm) AS act_dept_dt_tm,
( SELECT t1.scn, COUNT(t1.id) AS total_count_bl_status_c
FROM ccosbl t1
INNER JOIN vesvoy t2 ON t2.scn= t1.scn
WHERE t1.status_ind= 'C'
GROUP BY t1.scn)
FROM vesvoy t1
INNER JOIN ccosbl t2 ON t2.scn = t1.scn
WHERE t2.status_ind = 'C'
GROUP BY t1.scn,t1.vsl_name,t1.act_arr_dt_tm,t1.act_dept_dt_tm,t1.id
I need to combine both select statement as one. Is there any other ways to do that in sql?
If you insist on using a correlated subquery then you need to make sure that only one column is included into the select:
SELECT DISTINCT
t1.id,t1.scn,t1.vsl_name,case when t1.id = t1.id THEN 'IMPORT' ELSE '0' END AS import_export,
dbo.fn_format_datetime(t1.act_arr_dt_tm) AS act_arr_dt_tm,
dbo.fn_format_datetime(t1.act_dept_dt_tm) AS act_dept_dt_tm,
( SELECT COUNT(t4.id) AS total_count_bl_status_c
FROM ccosbl t4
INNER JOIN vesvoy t5 ON t4.scn= t5.scn
WHERE t1.status_ind= 'C' and t4.scn = t2.scn)
FROM vesvoy t1
INNER JOIN ccosbl t2 ON t2.scn = t1.scn
WHERE t2.status_ind = 'C'
GROUP BY t1.scn,t1.vsl_name,t1.act_arr_dt_tm,t1.act_dept_dt_tm,t1.id
However, the better approach will be to use a subquery with the join:
SELECT DISTINCT
t1.id,t1.scn,t1.vsl_name,case when t1.id = t1.id THEN 'IMPORT' ELSE '0' END AS import_export,
dbo.fn_format_datetime(t1.act_arr_dt_tm) AS act_arr_dt_tm,
dbo.fn_format_datetime(t1.act_dept_dt_tm) AS act_dept_dt_tm,
t3.total_count_bl_status_c
FROM vesvoy t1
INNER JOIN ccosbl t2 ON t2.scn = t1.scn
LEFT JOIN
( SELECT t4.scn, COUNT(t4.id) AS total_count_bl_status_c
FROM ccosbl t4
INNER JOIN vesvoy t5 ON t4.scn= t5.scn
WHERE t4.status_ind= 'C'
GROUP BY t4.scn) t3
ON t2.scn = t3.scn
WHERE t2.status_ind = 'C'
GROUP BY t1.scn,t1.vsl_name,t1.act_arr_dt_tm,t1.act_dept_dt_tm,t1.id
Try this:
SELECT t3.id t3.scn,total_count_bl_status_c,act_arr_dt_tm,act_dept_dt_tm,vsl_name,case when t3.id = t3.id THEN 'IMPORT' ELSE '0' END AS import_export,
dbo.fn_format_datetime(t3.act_arr_dt_tm) AS act_arr_dt_tm,
dbo.fn_format_datetime(t3.act_dept_dt_tm) AS act_dept_dt_tm from
(SELECT t2.scn, COUNT(t2.id) AS total_count_bl_status_c
FROM ccosbl t1
INNER JOIN
vesvoy t2
ON t2.scn= t1.scn
WHERE t1.status_ind= 'C'
GROUP BY t1.scn)as t3
inner join
(SELECT * from ccosbl) as t4 on
ON t4.scn = t3.scn

Performing a sum on rows with condition

I am trying to create a query like this
select sum(t1.quantity) - sum(t2.quantity * SELECT CASE WHEN (condition on t3.status) THEN 1 ELSE 0 END) ),0)
from table1 t1
inner join table2 t2 on t1.key = t2.key
inner join table3 t3 on t2.key = t3.key
Basically what it do is a subtraction between the first some and a second some of t2.quantity that are in rows that have a condition on the column t3.status (for example t3.status > 2).
But I am getting
Cannot perform an aggregate function on an expression containing an
aggregate or a subquery.
Is there a way to do this without adding extra join or other query?
I think this is what you are trying to do. You don't need a select again when using case as t3 is already joined.
select sum(t1.quantity) - sum(t2.quantity * CASE WHEN t3.status > 2 THEN 1 ELSE 0 END)
from table1 t1
inner join table2 t2 on t1.key = t2.key
inner join table3 t3 on t2.key = t3.key