SQL case when with equality and count conditions - sql

How can i perform a query with filtering both value and count of the element.Such as
Select
(case
when element = 'data1' and (select count(element) from mytable where element='data1') > 15 then '1'
when element = 'data2' and (select count(element) from mytable where element='data2') > 15 then '2'
.
.
.
)
from mytable
where conditions
are there any quick and simple ways to implement this?

I think you want window functions:
select (case when element = 'data1' and
count(*) over (partition by element) > 15
then '1'
when element = 'data2' and
count(*) over (partition by element) > 15
then '2'
.
.
.
)
from mytable
where conditions

For both code clarity and performance reason, I would separate the aggregating in a CTE and then invoke it in a join. If the table is big perhaps make sense you put the result in a temporary table instead of CTE for performance reasons.
;WITH ElementCTE
AS
(
SELECT element, count(Element) AS count_Element
FROM mytable
GROUP BY element
WHERE Conditions
)
SELECT
CASE ELEMENT
WHEN 'Data1' AND count_Element > 15 THEN '1'
WHEN 'Data2' AND count_Element > 15 THEN '2'
FROM mytable AS mt
INNER JOIN Element AS el
ON mt.Element = el.Element
WHERE mt.conditions

Assuming you have a table:
CREATE TABLE NULLTEST
(
TransactioNo INT,
Code VARCHAR(25)
)
INSERT INTO NULLTEST VALUES (NULL, 'TEST1');
INSERT INTO NULLTEST VALUES (NULL, 'TEST2');
INSERT INTO NULLTEST VALUES (1, 'TEST2');
The query could look like this:
SELECT
CASE
WHEN Code = 'TEST2' AND
(SELECT COUNT(1) FROM dbo.NULLTEST n WHERE n.Code = 'TEST2')> 1 THEN '1'
WHEN Code = 'TEST1' AND
(SELECT COUNT(1) FROM dbo.NULLTEST n WHERE n.Code ='TEST1')> 1 THEN '2'
ELSE '3' end Yourcolumn
FROM dbo.NULLTEST t
WHERE ...

Related

Get different query back based on a condition in PostgreSQL

I'm having a hard time with sql and probably this will look stupid but it shows what I am trying to achieve.
SELECT
CASE WHEN ( ( SELECT 1 FROM table_1 WHERE = condition ) IS NULL ) THEN
SELECT 'No result'::varchar
ELSE
SELECT
val_1,
val_2,
val_3
FROM
table_1
END;
A null answer is not good in my situation, I can't just use the sub-query as the main. And even if I could that would still leave the question open if the two tables were NOT the same like:
SELECT
CASE WHEN ( ( SELECT 1 FROM table_1 WHERE = condition ) IS NULL ) THEN
SELECT 'No result'::varchar
ELSE
SELECT
val_1,
val_2,
val_3
FROM
table_2 --TABLE REPLACED!
END;
As CASE-WHEN only works for one column it would be horrifying to have 20 of them with the same condition. Any help is appreciated! Thanks!
So you want to SELECT the table_log and if the result is not NULL show it to the client and if it is NULL show a message?
I created a fake table for testing. What you are looking for is the last SELECT-statement:
DROP TABLE IF EXISTS table_log;
CREATE TEMP TABLE table_log (
id INTEGER
,log_info VARCHAR)
;
INSERT INTO table_log VALUES
(1, 'test_entry')
;
ANALYZE table_log;
SELECT
COALESCE(b.log_info, 'No changes done!') AS log_info
FROM
(SELECT 'Fake-Data') a
LEFT OUTER JOIN (SELECT * FROM table_log WHERE id = 1) b ON (1=1);
If the given id = 1, you get the result, if it is something else (because it is not in the test-table) the premade message is given.
Here is a link to the db<>fiddle.

Group by absorb NULL unless it's the only value

I'm trying to group by a primary column and a secondary column. I want to ignore NULL in the secondary column unless it's the only value.
CREATE TABLE #tempx1 ( Id INT, [Foo] VARCHAR(10), OtherKeyId INT );
INSERT INTO #tempx1 ([Id],[Foo],[OtherKeyId]) VALUES
(1, 'A', NULL),
(2, 'B', NULL),
(3, 'B', 1),
(4, 'C', NULL),
(5, 'C', 1),
(6, 'C', 2);
I'm trying to get output like
Foo OtherKeyId
A NULL
B 1
C 1
C 2
This question is similar, but takes the MAX of the column I want, so it ignores other non-NULL values and won't work.
I tried to work out something based on this question, but I don't quite understand what that query does and can't get my output to work
-- Doesn't include Foo='A', creates duplicates for 'B' and 'C'
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY [Foo] ORDER BY [OtherKeyId]) rn1
FROM #tempx1
)
SELECT c1.[Foo], c1.[OtherKeyId], c1.rn1
FROM cte c1
INNER JOIN cte c2 ON c2.[OtherKeyId] = c1.[OtherKeyId] AND c2.rn1 = c1.rn1
This is for a modern SQL Server: Microsoft SQL Server 2019
You can use a GROUP BY expression with HAVING clause like below one
SELECT [Foo],[OtherKeyId]
FROM #tempx1 t
GROUP BY [Foo],[OtherKeyId]
HAVING SUM(CASE WHEN [OtherKeyId] IS NULL THEN 0 END) IS NULL
OR ( SELECT COUNT(*) FROM #tempx1 WHERE [Foo] = t.[Foo] ) = 1
Demo
Hmmm . . . I think you want filtering:
select t.*
from #tempx1 t
where t.otherkeyid is not null or
not exists (select 1
from #tempx1 t2
where t2.foo = t.foo and t2.otherkeyid is not null
);
My actual problem is a bit more complicated than presented here, I ended up using the idea from Barbaros Özhan solution to count the number of items. This ends up with two inner queries on the data set with two different GROUP BY. I'm able to get the results I need on my real dataset using a query like the following:
SELECT
a.[Foo],
b.[OtherKeyId]
FROM (
SELECT
[Foo],
COUNT([OtherKeyId]) [C]
FROM #tempx1 t
GROUP BY [Foo]
) a
JOIN (
SELECT
[Foo],
[OtherKeyId]
FROM #tempx1 t
GROUP BY [Foo], [OtherKeyId]
) b ON b.[Foo] = a.[Foo]
WHERE
(b.[OtherKeyId] IS NULL AND a.[C] = 0)
OR (b.[OtherKeyId] IS NOT NULL AND a.[C] > 0)

SQL: Finding values in sets, that only appear once

Using Oracle SQL, I need to find the IDs (ICFPROKEYI) that occur more then once, but have a certain field (ICFFLDC) only once:
ICFPROKEYI|ICFKAVKEYI|ICFNUMS|ICFFLDC
----------|----------|-------|-----------------------------
2234884| 5887| 0|Farbe.14870
2234884| 5887| 1|Ueberschrift_i_24291101.18563
2234884| 5888| 0|Farbe.14870
2234884| 5889| 0|Farbe.14870
2234884| 5890| 0|Farbe.14870
2234884| 5896| 0|Farbe.14870
In this case, 2234884, because it appears 6 times but has a value (Ueberschrift_i_24291101.18563) appear only once
You can try this:
select a.ICFPROKEYI from table a join table b
on a.ICFPROKEYI = b.ICFPROKEYI and a.ICFFLDC <> b.ICFFLDC
GROUP BY icfprokeyi and use HAVING count(*) > 1 to get the icfprokeyi that appear more than once and GROUP BY icfprokeyi, icffldc and use HAVING count(*) = 1 to get the icfprokeyi where the icffldc doesn't exist in another row with the same icfprokeyi. Then join both aggregations.
SELECT x1.icfprokeyi
FROM (SELECT t1.icfprokeyi
FROM elbat t1
GROUP BY t1.icfprokeyi
HAVING count(*) > 1) x1
INNER JOIN (SELECT t2.icfprokeyi
FROM elbat t2
GROUP BY t2.icfprokeyi,
t2.icffldc
HAVING count(*) = 1) x2
ON x2.icfprokeyi = x1.icfprokeyi;
Here is the postgres query:
select ICFPROKEYI,ICFFLDC from table group by ICFPROKEYI,ICFFLDC having count(*)=1;
Help yourself to write the oracle equivalent for it.
I've tried this with MySQL and might be applicable in oracle as well.
SELECT ICFPROKEYI
FROM <yourtable> WHERE ICFPROKEYI IN
(
SELECT ICFPROKEYI
FROM <yourtable>
GROUP BY ICFPROKEYI
HAVING COUNT(ICFPROKEYI) > 1
)
GROUP BY ICFPROKEYI, ICFFLDC
HAVING cnt(ICFFLDC) = 1
You can simply use GROUP BY with HAVING (two conditions) as following:
SELECT
ICFPROKEYI
FROM <yourtable>
GROUP BY ICFPROKEYI
HAVING COUNT(1) > 1
AND SUM(CASE WHEN ICFFLDC = 'Ueberschrift_i_24291101.18563'
THEN 1 END) = 1
-- Update
After #ankit specified that it can be any value(not fixed value - Ueberschrift_i_24291101.18563), OP can achieve the desired result using following query:
SELECT ICFPROKEYI
FROM
( SELECT T.ICFPROKEYI,
COUNT(1) OVER(
PARTITION BY T.ICFPROKEYI, ICFFLDC
) AS CNT
FROM YOURTABLE T
)
WHERE CNT = 1
Cheers!!
I have replicated this on my local, please find the below SQL block and try it yourself
drop table test;
CREATE TABLE test(
ICFPROKEYI INTEGER NOT NULL
,ICFKAVKEYI INTEGER NOT NULL
,ICFNUMS number(1,0) NOT NULL
,ICFFLDC VARCHAR(30) NOT NULL
);
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5887,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5887,1,'Ueberschrift_i_24291101.18563');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5888,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5889,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5888,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234884,5889,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234885,5890,0,'Farbe.14870');
INSERT INTO test(ICFPROKEYI,ICFKAVKEYI,ICFNUMS,ICFFLDC) VALUES (2234885,5896,0,'Farbe.14870');
Query
SELECT A.ICFPROKEYI FROM (select ICFPROKEYI,ICFFLDC, count(*) AS ICFFLDC_CNT from test
group by ICFPROKEYI,ICFFLDC)A LEFT OUTER JOIN
(select ICFPROKEYI,count(*) as ICFPROKEYI_CNT from test group by ICFPROKEYI)B
ON A.ICFPROKEYI = B.ICFPROKEYI WHERE A.ICFFLDC_CNT = 1AND B.ICFPROKEYI_CNT > 1 ;

Why does this query result in a "missing FROM clause"?

Why below sql statement keeps getting missing FROM clause entry for table error?
How to adjust this?
WITH SUBID AS (
SELECT * FROM "B_COLLECTION"."COLL_C_RECORD"
),
TR AS (
SELECT * FROM "B_TRACE"."PERSONAL_TC_RECORD"
)
SELECT "SUBJECT_C_ID"
FROM "B_COLLECTION"."COLL_C_RECORD"
WHERE ( SUBID.SUBJECT_ID = TR.PERSONAL_S_ID )
AND ( TR.STATE_ID ='5' OR TR.STATE_ID = 'A' OR TR.STATE_ID = 'C');
You are declaring SUBID and TR just fine, but since these are tables, your select statement does not know them yet.
Here you need to enter SUBID and TR in FROM clauses of your query. It should look somewhat like
WITH SUBID AS (
SELECT * FROM "B_COLLECTION"."COLL_C_RECORD"
) ,
TR AS (
SELECT * FROM "B_TRACE"."PERSONAL_TC_RECORD"
)
SELECT "SUBJECT_C_ID" FROM SUBID
WHERE SUBID."SUBJECT_ID" IN
(SELECT "PERSONAL_S_ID" FROM TR
WHERE TR."STATE_ID" = '5'
OR TR."STATE_ID" = 'A'
OR TR."STATE_ID" = 'C');
That is why you use WITH Clause only on repeating queries. Here it would actually be much nicier to use:
SELECT "SUBJECT_ID" FROM "B_COLLECTION"."COLL_C_RECORD" SUBID
WHERE SUBID."SUBJECT_ID" IN
(SELECT "PERSONAL_S_ID" FROM "B_TRACE"."PERSONAL_TC_RECORD" TR
WHERE TR."STATE_ID" = '5'
OR TR."STATE_ID" = 'A'
OR TR."STATE_ID" = 'C');

SQL Insert assistance

I have this query:
insert into OrderCounts (OpenOrders,ReadyOrders)
select t1.OpenOrders, t2.ReadyOrders
from
(select count(distinct(info.orderid)) as OpenOrders from LabworksDBProDPI.DBO.orderinfo info where info.orderstatusID = '1') t1,
(select count(distinct(info.orderid)) as ReadyOrders from LabworksDBProDPI.DBO.orderinfo info where info.orderstatusID = '2') t2
I have three columns: Openorders, ready orders, Period
When I run this query I want to enter into the Period column the text of "PM". I am not sure how to combine my query with the static text of "PM"
Just include it in the select:
insert into OrderCounts (OpenOrders, ReadyOrders, Period)
select t1.OpenOrders, t2.ReadyOrders, 'PM'
from (select count(distinct info.orderid) as OpenOrders
from LabworksDBProDPI.DBO.orderinfo info
where info.orderstatusID = '1'
) t1 cross join
(select count(distinct info.orderid) as ReadyOrders
from LabworksDBProDPI.DBO.orderinfo info
where info.orderstatusID = '2'
) t2;
You could, of course, write this without the subqueries:
insert into OrderCounts (OpenOrders, ReadyOrders, Period)
select count(distinct case when i.orderStatusId = 1 then i.orderid end),
count(distinct case when i.orderStatusId = 2 then i.orderid end),
'PM'
from LabworksDBProDPI.DBO.orderinfo info i
where i.orderstatusID in (1, 2);