Left join two tables returning null values - sql

I have these 2 tables #tmp and #tmp1:
I am writing a query like,
SELECT
repperiod, sequence, t1.title, question,
(CASE WHEN t2.Answer = 1 THEN 1 ELSE 0 END) Met,
(CASE WHEN t2.Answer = 3 THEN 1 ELSE 0 END) NA,
(CASE WHEN (ISNULL(t2.Answer,3) <> 3) THEN 1 ELSE 0 END) MetNotMet
FROM
#tmp t1
LEFT OUTER JOIN
#temp1 t2 ON t1.ScheduleQuestionID = t2.ScheduleQuestionID
AND t1.deptsplit = t2.DeptSplit
It's returning Met, NA, MetNotMet with NULL values.
What's wrong in the query?
#tmp has more rows than #tmp1. So not all Question Ids from #tmp are present in #tmp1.
Some records have multiple answers for same question. so I am splitting by dept.
I want to take all rows from #tmp. So I am creating left join.

Related

IN/EXISTS predicate sub-queries can only be used in Filter/Join and a few commands

I am trying to write a query in azure databricks and I am getting the following error
"IN/EXISTS predicate sub-queries can only be used in Filter/Join and a few commands"
This is the code I am using.
SELECT id,
(CASE WHEN id in (SELECT id from aTable) THEN 1 ELSE 0 END) as a,
(CASE WHEN id in (SELECT id from bTable) THEN 1 ELSE 0 END) as b,
(CASE WHEN id in (SELECT id from cTable) THEN 1 ELSE 0 END) as c
FROM table
I read that sql doesn't let you do this because the case statements are evaluated row by row, and it wants to prevent you from doing a SELECT statement for each row evaluation. If that is the case, is there an alternative or workaround to accomplish this? Thanks
Databricks does not support subqueries using IN or EXISTS in CASE statements. As an alternative, consider outer joining each view to master table:
Query could be like then structure below:
select .....
case when a.id is not null then a
when b.id is not null then b
end as id
from Table_t t LEFT JOIN (select id from aTable ) a ON t.id=a.id LEFT JOIN(
select id from bTable) b ON t.id=b.id
..................
I tried to reproduce similar scenario and got same error:
Regardless of whether it is contained in a CASE WHEN, the IN operator utilising a subquery only functions in filters, not projections. If you explicitly supply values in the IN clause as opposed to using a subquery, it works just great.
To work around this, I tried left join to tables and then check for a null in the case statement.
This query might work
%sql
SELECT t.Id,
(CASE WHEN at.Id is not null THEN 1 ELSE 0 END) as a,
(CASE WHEN bt.Id is not null THEN 1 ELSE 0 END) as b,
(CASE WHEN ct.Id is not null THEN 1 ELSE 0 END) as c
FROM table t
LEFT JOIN aTable at ON t.Id = at.Id
LEFT JOIN bTable bt ON t.Id = bt.Id
LEFT JOIN cTable ct ON t.Id = ct.Id
Sample data:
Output:

Oracle SQL - implement logic based on CASE expression result

I have following query which returns me of percentage of rows with at least one NULL in any of columns:
SELECT
(SUM(CASE WHEN tablea.test IS NULL OR tableb.test IS NULL THEN 1 ELSE NULL END)/7000)*100) "at least one NULL (%)"
FROM tablea
FULL OUTER JOIN tableb
ON
tablea.test = tableb.test
WHERE ROWNUM < 7000;
Query works fine to me and I am getting valid result.
But I need to do further action in tablec, based on percentage calculated in my SELECT statement. If percentage of rows with NULL is below 30% I need to insert "YES" string inside table "tablec" column "resultcol", how can I implement such a logic?
Is it for example possible to store SELECT statement result in some temporary variable which will be used in another SQL query?
You can use:
INSERT INTO tablec (resultcol)
SELECT 'YES'
FROM tablea
FULL OUTER JOIN tableb
ON tablea.test = tableb.test
WHERE ROWNUM < 7000
HAVING COUNT(CASE WHEN tablea.test IS NULL OR tableb.test IS NULL THEN 1 END)
< COUNT(*) * 0.3;
db<>fiddle here
Update:
If you want to insert a row if it does not exist or change the row if it does exist then:
MERGE INTO tablec dst
USING (
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM tablea
FULL OUTER JOIN tableb
ON tablea.test = tableb.test
WHERE ROWNUM < 7000
HAVING COUNT(CASE WHEN tablea.test IS NULL OR tableb.test IS NULL THEN 1 END)
< COUNT(*) * 0.3
)
THEN 'YES'
ELSE 'NO'
END AS resultcol
FROM DUAL
) src
ON (1 = 1)
WHEN NOT MATCHED THEN
INSERT (resultcol) VALUES (src.resultcol)
WHEN MATCHED THEN
UPDATE SET resultcol = src.resultcol;
Or, to just update it:
UPDATE tablec
SET resultcol = CASE
WHEN EXISTS (
SELECT 1
FROM tablea
FULL OUTER JOIN tableb
ON tablea.test = tableb.test
WHERE ROWNUM < 7000
HAVING COUNT(
CASE
WHEN tablea.test IS NULL
OR tableb.test IS NULL
THEN 1
END
) < COUNT(*) * 0.3
)
THEN 'YES'
ELSE 'NO'
END;
db<>fiddle here

How to avoid `missing expression` error in sql

I'd like to count number of each product by following sql
but I suffered following error..
ORA-00936: Missing Expression
Where is wrong with my sql.
If someone has opinion,please let me know.
Thanks
select t.customer,
count(case when left(t.product,2)='AD' then 1 end) as A,
count(case when left(t.product,1)='F' then 1 end) as B,
count(case when left(t.product,1)='H' then 1 end) as C,
from table t
left join table2 t2
on t.customer = t2.customer
where t2.type='VLI'
group by t.customer
Oracle doesn't have LEFT() function while MySQL does, use SUBSTR() instead. And remove the comma, which's typo , at the end of the fourth line
SELECT t.customer,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 2) = 'AD' THEN
1
END) AS A,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 1) = 'F' THEN
1
END) AS B,
COUNT(CASE
WHEN SUBSTR(t.product, 1, 1) = 'H' THEN
1
END) AS C
FROM yourtable t
LEFT JOIN table2 t2
ON t.customer = t2.customer
WHERE t2.type = 'VLI'
GROUP BY t.customer
You have extra comma in row count(case when left(t.product,1)='H' then 1 end) as C,.
Delete the last comma and this error will go away.
I would suggest LIKE:
select t.customer,
sum(case when t.product like 'AD%' then 1 else 0 end) as A,
sum(case when t.product like 'F%' then 1 else 0 end) as B,
sum(case when t.product like 'H%' then 1 else 0 end) as C
from table t left join
table2 t2
on t.customer = t2.customer and t2.type='VLI'
group by t.customer;
Notes:
With like, you don't have to worry about an argument to a substring function matching the length of the matched string. I learned about the issues of inconsistencies there a long, long, long time ago.
I prefer sum() in this case over count(), but that is mostly aesthetic.
You are using a left join, but filtering in the where clause. This turns the join into an inner join. Either change the join to inner join or move the condition to the on clause (as this does).

SQL JOIN WITH TWO WHERE CLAUSES

I would like to implement the following SQL query : suppose using JOIN clause, due to now it's running quite slow:
SELECT ID_USER, NICK
FROM TABLE1
WHERE ID_USER IN
(
SELECT ID_INDEX1
FROM TABLE2
WHERE ID_INDEX2 = '2'
)
AND ID_USER NOT IN
(
SELECT ID_INDEX2
FROM TABLE2
WHERE ID_INDEX1 = '2' AND GO ='NO'
)
ORDER BY NICK ASC
You could do the "including" part with INNER JOIN and the "excluding" part with a "LEFT JOIN" + filtering:
SELECT DISTINCT t1.ID_USER, t1.NICK
FROM TABLE1 t1
INNER JOIN TABLE2 t2IN
ON t1.ID_USER = t2IN.ID_INDEX1
AND t2IN.ID_INDEX2 = '2'
LEFT JOIN TABLE2 t2OUT
ON t1.ID_USER = t2OUT.ID_INDEX2
AND t2OUT.ID_INDEX1 = '2'
AND t2OUT.GO = 'NO'
WHERE t2OUT.ID_INDEX IS NULL
ORDER BY t1.NICK ASC
Assuming that you want to filter by ID_INDEX1 in both cases (see my comment on your question), you can:
count the number of rows per user in table2 with value = 2
count the number of rows per user in table2 with value = 2 and go = 'NO'
return only those for which the first count is greater than 0 and the second count equals 0
i.e.:
select * from (
select
id_user,
nick,
sum(case when table2.id_index2 = '2' then 1 else 0 end) as count2_overall,
sum(case when table2.id_index2 = '2' and go = 'NO' then 1 else 0 end) as count2_no
from table1
join table2 on table1.id_user = table2.id_index1
group by id_user, nick
)
where count2_overall > 0 and count2_no = 0

GROUP BY CLAUSE USE

I have a table with different payment method types: CHECK, MONEY ORDER, CASH. I need to show the break down of different payment types, following is my query. Could anyone suggest or comment how to do it optimally.
select
COUNT(T3.PAY_METHOD),
T1.CLAIM_ID
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T3.PAYMENT_METHOD_CD
Following is output column should look
|CHECK|MONEY ORDER|CASHIER'S CHECK|CASH|CREDIT CARD|
Displays the total count of all payments received via CHECK that were applied to the specific LIABLE INDIVIDUAL.
If you really need the output as columns, then you will want to use a SUM(case when method = '' then 0 else 1 end) type solution. Like this.
select t1.claim_id,
sum(case when t3.pay_method = 'CASH' then 1 else 0 end) as "CASH",
sum(case when t3.pay_method = 'MONEY ORDER' then 1 else 0 end) as "MONEY ORDER",
sum(case when t3.pay_method = 'CHECK' then 1 else 0 end) as "CHECK",
T1.CLAIM_ID
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T1.CLAIM_ID
But it would be much simpler if you just want them each as rows.
select T1.CLAIM_ID, T3.PAY_METHOD, COUNT(*)
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T1.CLAIM_ID, T3.PAY_METHOD
sql would be:
select T3.PAY_METHOD
, COUNT(T3.PAY_METHOD) records
from TB1 T3
JOIN TB2 T2 ON T3.CLAIM_ID = T2.CLAIM_ID
GROUP BY T3.PAY_METHOD
You can use application code to format the output.