Case( select) when then - sql

The query is compiled correctly. Prompt how to make correctly. You need to get three variables and check them out. Depending on the selected test date.
after when is not written correctly
select sum(t.sum),t3.cost, t.status
from Credit t inner join cost t3 on t.code= t3.code1
where t.id='1' and
t.date >= case (SELECT t1.mark1, t1.mark2, t2.mark3
FROM marks t1 INNER JOIN marksagain t2 ON (t1.id = t2.id)
WHERE t1.id = t.id)
when (0,0,6) then (INTNX('month',date(),6,'same'))
else(INTNX('month',date(),3,'same')) end
group by t.sum, t3.cost, t.status;`

Try out this:
select sum(t.sum),t3.cost, t.status
from Credit t inner join cost t3 on t.code= t3.code1
where t.id='1' and t.date >=
case when (SELECT t1.mark1 FROM marks t1 INNER JOIN marksagain t2 ON (t1.id = t2.id) WHERE t1.id = t.id) = 0
AND (SELECT t1.mark2 FROM marks t1 INNER JOIN marksagain t2 ON (t1.id = t2.id) WHERE t1.id = t.id) = 0
AND (SELECT t2.mark3 FROM marks t1 INNER JOIN marksagain t2 ON (t1.id = t2.id) WHERE t1.id = t.id) = 6
then (INTNX('month',date(),6,'same')) else(INTNX('month',date(),3,'same'))
end
group by t.sum, t3.cost, t.status;

Related

SQL three table joins using two ids and another column

I have three tables
t1 t2 t3
I want to select data from only two of the tables but need the ids and columns from other tables for reference.
How to select data from t3 and t2
WHERE t1.id = t2.id = t3.id
AND t1.fid = t2.fid = t3.fid
AND t1.type = 'abc'
id column will be the same value for all tables. fid column will have incremental fid's but need the ones where t1.type = 'abc' also
Would this work?
select data
from t3
select data
from t2
join on t1.id = t2.id and t2.id = t3.id
join on t1.fid = t2.fid and t2.fid = t3.fid and t1.type = 'abc'
where id = 1
Generally, this kind of problem can be solved using EXISTS as follows:
select data
from t2
join t1 on t1.id = t2.id and t1.fid = t2.fid
where exists (select 1 from t3 where t2.id = t3.id and t2.fid = t3.fid)
and t1.type = 'abc'
and t1.id = 1
You could try something like this:
select columns_that_you_want
from t1 x
inner join t2 y on x.id = y.id
inner join t3 z on y.id = z.id
where x.type = 'abc'
;
This will join the three tables, and filter just the type 'abc' that you want from table t1. Also you can add more filter on the where clause in case you need to filter more the result.

Is there any way to get away without writing a left join subquery twice?

My SQL isn't as strong as it could be. It's a different way of thinking compared to writing C#. I'm working on a query and rewriting it using "left join/is null" to get away from the "not in" syntax.
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join (select sub.id from ratherLargeSubquery sub) s1
On s1.id = t1.id
left join (select sub.id from ratherLargeSubquery sub) s2
On s2.id = t2.id
where
s1.id is null and
s2.id is null
Is there any way to get away from writing ratherLargeSubquery twice? I've tried
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join (select sub.id from ratherLargeSubquery sub) s1
On (s1.id = t1.id and t2.id = s1.id)
where
s1.id is null
but of course that returns the same results as if I never added the left join in the first place and
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join (select sub.id from ratherLargeSubquery sub) s1
On (s1.id = t1.id or s1.id = t2.id)
where
s1.id is null
Just runs for over 20 times the length of time of the original query without every returning any results.
Back to the question, is there any way to write it without writing ratherLargeSubquery twice
I almost hesitate to post this given that many knowledgeable posters have not mentioned it, but why not a common table expression?
I gather your true objection is not having two left joins but having to duplicate the logic of "ratherLargeSubquery".
with cte AS ( SELECT sub.id FROM ratherLargeSubquery sub )
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join cte s1
On s1.id = t1.id
left join cte s2
On s2.id = t2.id
where
s1.id is null and
s2.id is null
Because you are not selecting any columns from the subquery, you can move the filtering to the where clause.
select t1.id, t2.col1
from table1 t1 join
table2 t2
on t1.id = t2.id
where not exists (select 1
from ratherLargeSubquery sub
where sub.id = t1.id or sub.id = t2.id
);
This simplifies writing the query. However, Oracle may have trouble optimizing it.
It seems that the SQL actually doesn't need the 2nd left join.
Because t1.id = t2.id
So then s1.id = s2.id
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join (select id from ratherLargeSubquery) s1
on s1.id = t1.id
where s1.id is null
Use s.id in (t1.id, t2.id) for the join condition:
select t1.id, t2.col1
from table1 t1
join table2 t2 on t1.id = t2.id
left join (select sub.id from ratherLargeSubquery sub) s
on s.id in (t1.id, t2.id)
where s.id is null

Merging different conditional select queries into one - with structure

I have a query in SQL Server 2008 as below:
;with PassiveCases
AS
(
Select t1.id, COUNT(*) as PassiveCounts
from #Table1 t1
inner join Table2 t2 on t2.Id = t1.SurgicalRequest_Id
inner join Table3 t3 on t3.Id = t2.ReportingIndicator_Id
inner join Table3 t4 on t4.Id = t3.Id
where t4.Passive = 1
),
ActiveCases
AS
(
Select t1.id, COUNT(*) as ActiveCounts
from #Table1 t1
inner join Table2 t2 on t2.Id = t1.SurgicalRequest_Id
inner join Table3 t3 on t3.Id = t2.ReportingIndicator_Id
inner join Table3 t4 on t4.Id = t3.Id
where t4.Passive = 0
)
What I want it to combine these structures into one to increase the efficiency and provide more readability. I am looking for something like below (it doesn't work)
:With Cases
AS
(
Select t1.id, case when t4.Passive = 1 then COUNT(*) as PassiveCounts else COUNT(*) as ActiveCounts
from #Table1 t1
inner join Table2 t2 on t2.Id = t1.SurgicalRequest_Id
inner join Table3 t3 on t3.Id = t2.ReportingIndicator_Id
inner join Table3 t4 on t4.Id = t3.Id
)
Any help would be appreciated.
Use conditional aggregation.
Select t1.id
,sum(case when t4.Passive = 1 then 1 else 0 end) as PassiveCounts
,sum(case when t4.Passive <> 1 then 1 else 0 end) as ActiveCounts
from #Table1 t1
inner join Table2 t2 on t2.Id = t1.SurgicalRequest_Id
inner join Table3 t3 on t3.Id = t2.ReportingIndicator_Id
inner join Table3 t4 on t4.Id = t3.Id
group by t1.id
You just want conditional aggregation. In your case, though, you can do this with arithmetic:
With Cases AS (
Select t1.id, sum(t4.Passive) as PassiveCount, sum(1 - t4.Passive) as ActiveCount
from #Table1 t1 inner join
Table2 t2
on t2.Id = t1.SurgicalRequest_Id inner join
Table3 t3
on t3.Id = t2.ReportingIndicator_Id inner join
Table3 t4
on t4.Id = t3.Id
group by t1.id
)
According to your question, t4.Passive only takes on two values, so the arithmetic should do what you want.

Oracle SQL: JOIN by dblink

I use next SQL-query in Oracle DB:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN MyTable3#dblink1 T3 ON T3.Id2 = T2.Id
This query is very simple and fast (about 1 min, T1 contain about 1 million rows, T3 more then 10 million rows). Now I want to use MyTable4 from dblink1 for filtering selected rows data. For it, I use subquery:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN (SELECT Sub_T1.*
FROM MyTable3#dblink1 Sub_T1
INNER JOIN MyTable4#dblink1 Sub_T2 ON Sub_T2.Id3 = Sub_T1.Id
WHERE
Sub_T2.MyColumn1 = 'required value') T3 ON T3.Id2 = T2.Id
But this query is too slow (more then 20min). If I rewrite this query to:
SELECT T1.*,
T3.*
FROM MyTable1 T1
INNER JOIN MyTable2 T2 ON T2.Id1 = T1.Id
LEFT JOIN MyTable3#dblink1 T3 ON T3.Id2 = T2.Id
LEFT JOIN MyTable4#dblink1 T4 ON T4.Id3 = T3.Id
WHERE
T4.MyColumn1 = 'required value'
Then my query work fast again, but I donn't like result (I want to see columns of T3 as null, if WHERE return false).
How to improve my second query, for speed up it?
Does phrasing the query with parentheses solve the problem?
SELECT T1.*,
T3.*
FROM MyTable1 T1 INNER JOIN
MyTable2 T2
ON T2.Id1 = T1.Id LEFT JOIN
(MyTable3#dblink1 T3 JOIN
MyTable4#dblink1 T4
ON T4.Id3 = T3.Id AND
T4.MyColumn1 = 'required value'
)
ON T3.Id2 = T2.Id;
Or, also:
SELECT T1.*,
T3.*
FROM MyTable1 T1 INNER JOIN
MyTable2 T2
ON T2.Id1 = T1.Id LEFT JOIN
MyTable3#dblink1 T3
ON T3.Id2 = T2.Id
EXISTS (SELECT 1 FROM MyTable4#dblink1 T4 WHERE T4.Id3 = T3.Id AND T4.MyColumn1 = 'required value'
)

Combining INNER JOIN and LEFT JOIN

Edited
I'm not asking How to write good query but those 3 queries return same results.
Query 1
SELECT v1.id
FROM (
SELECT DISTINCT t1.id
FROM t1 LEFT JOIN t2 ON t1.id = t2.id
WHERE t2.id IS NULL
) v1 INNER JOIN (
SELECT DISTINCT t3.id
FROM t3 LEFT JOIN t4 ON t3.id = t4.id
WHERE t4.id IS NULL
) v2 ON v1.id = v2.id;
Query 2
SELECT DISTINCT t1.id
FROM (t1 LEFT JOIN t2 ON t1.id = t2.id)
INNER JOIN (t3 LEFT JOIN t4 ON t3.id = t4.id) ON t1.id = t3.id
WHERE t2.id IS NULL AND t4.id IS NULL;
Query 3
SELECT DISTINCT t1.id
FROM t1 LEFT JOIN t2 ON t1.id = t2.id
INNER JOIN t3 ON t1.id = t3.id LEFT JOIN t4 ON t3.id = t4.id
WHERE t2.id IS NULL AND t4.id IS NULL;
Queries are not hard coded by programmer but generate dynamically by user input.
For example when user inserts find id in t1 (but not in t2) and in t3 (but not in t4), his indention is Query 1. But currently my program generates Query 3 and it looks like OK. I'm wondering this query has a bug in some cases, so that should be changed like Query 2 or 1.
User input (shown above) is just example and converting user input to JOIN statement is difficult at last to me.
Thanks in advanced.
This is the original query:
SELECT v1.id
FROM (SELECT DISTINCT t1.id
FROM t1 LEFT JOIN t2 ON t1.id = t2.id
WHERE t2.id IS NULL
) v1 INNER JOIN
(SELECT DISTINCT t3.id
FROM t3 LEFT JOIN t4 ON t3.id = t4.id
WHERE t4.id IS NULL
) v2
ON v1.id = v2.id;
If I understand correctly, you want ids that are in t1 and t3, but not in t2 and t4.
I would express the second query as:
SELECT distinct t1.id
FROM t1 INNER JOIN
t3
on t1.id = t3.id LEFT JOIN
t2
on t1.id = t2.id LEFT JOIN
t4
on t1.id = t4.id
WHERE t2.id IS NULL AND t4.id IS NULL;
I read your original query as asking for "all ids in T1 which are in both T1 and T3 but not in T2 or T4". Is that correct? If so, my query would be:
SELECT DISTINCT t1.id
FROM t1
WHERE EXISTS (SELECT 1 FROM t3 WHERE t1.id = t3.id)
AND NOT EXISTS (SELECT 1 FROM t2 WHERE t1.id = t2.id)
AND NOT EXISTS (SELECT 1 FROM t4 WHERE t1.id = t4.id)
Not sure what the real objective is, nor which dbms is being targeted
-- oracle
SELECT id FROM ( SELECT id FROM t1 MINUS SELECT id FROM t2 ) a
INTERSECT
SELECT id FROM ( SELECT id FROM t3 MINUS SELECT id FROM t4 ) b
;
-- sql server
SELECT id FROM ( SELECT id FROM t1 EXCEPT SELECT id FROM t2 ) a
INTERSECT
SELECT id FROM ( SELECT id FROM t3 EXCEPT SELECT id FROM t4 ) b
;
SELECT c.id from (
SELECT t1.id
FROM t1 LEFT JOIN t2 ON t1.id = t2.id
WHERE t2.id IS NULL
UNION ALL
SELECT t3.id
FROM t3 LEFT JOIN t4 ON t3.id = t4.id
WHERE t4.id IS NULL
) c GROUP BY c.id HAVING count(*) >= 2
;
The next one is potentially quite efficient BUT has a caveat
-- conditions apply, assumes t2 and t4 cannot have ids not in t1 or t3 respectively
SELECT c.id from (
SELECT a.id from (
(SELECT ID FROM T1)
UNION ALL
(SELECT ID FROM T2)
) a GROUP BY a.id HAVING count(*) = 1
UNION ALL
SELECT b.id from (
(SELECT ID FROM T3)
UNION ALL
(SELECT ID FROM T4)
) b GROUP BY b.id HAVING count(*) = 1
) c GROUP BY c.id HAVING count(*) >= 2
;
Fiddles:
| Oracle
| SQL Server |
MySQL |