T-sql: calculate sum of factors when quantity of factors can differ from time to time - sql

Would you please, help me, to develop the algorythm of counting rating of the clients.
Initial dataset and desirable result is in the code below. Thank you.
The logic:
We have clients and 6 factors (with values 1 or 0 (present or not present)).
We should calculate a rating of the client:
1 (max rate) - client has all the factors
2 - client has factors 1-5 and doesn't have 6th
3 - client has factors 1-4 and doesn't have 5th (factor 6 doesn't matter)
4 - client has factors 1-3 and doesn't have 4th (factors 5-6 don't matter)
5 - client has factors 1-2 and doesn't have 3rd (factors 4-6 don't matter)
6 - client has factor 1 and doesn't have 2nd (factors 3-6 don't matter)
7 - client doesnt have factor 1 (factors 2-6 don't matter)
The key is that number of factors can differ from time to time.
drop table if exists #tmp;
create TABLE #tmp (
[client] [nvarchar] null,
[factor1] [int] NULL,
[factor2] [int] NULL,
[factor3] [int] NULL,
[factor4] [int] NULL,
[factor5] [int] NULL,
[factor6] [int] null,
[desirable_result] [int] NULL
)
insert into #tmp (
[client]
,[factor1]
,[factor2]
,[factor3]
,[factor4]
,[factor5]
,[factor6]
,[desirable_result]
)
select '1', 1,1,1,1,1,1,1 union all
select '2', 1,1,0,1,1,1,5 union all
select '3', 1,0,1,1,0,1,6 union all
select '4', 1,1,1,1,1,0,2 union all
select '5', 1,1,1,0,0,1,4
This solution works, but only if the num of factors is always equal.
The key is that number of factors can differ from time to time.
select *
, "factor1" + "factor2" + "factor3" + "factor4" + "factor5" + "factor6" sum_6
, "factor1" + "factor2" + "factor3" + "factor4" + "factor5" sum_5
, "factor1" + "factor2" + "factor3" + "factor4" sum_4
, "factor1" + "factor2" + "factor3" sum_3
, "factor1" + "factor2" sum_2
, "factor1" sum_1
into #tmp2
from #tmp
select *
, case when sum_6 = 6 then 1 else
(case when sum_5 = 5 and sum_6 < 6 then 2 else
(case when sum_4 = 4 and sum_5 < 5 then 3 else
(case when sum_3 = 3 and sum_4 < 4 then 4 else
(case when sum_2 = 2 and sum_3 < 3 then 5 else
(case when sum_1 = 1 and sum_2 < 2 then 6 else
7
end)
end)
end)
end)
end)
end rate
from
#tmp2

you can use CASE WHEN ... as what scaisEdge has demonstrated.
What i have here is to UNPIVOT the table using CROSS APPLY and then using SUM() with CASE to workout the necessary logic
select t.client,
t.[desirable_result],
case when sum(f.fval) = 6 then 1
when sum(f.fval) = 5
and sum(case when f.fno = 6 then f.fval end) = 0 then 2
when sum(case when f.fno <= 4 then f.fval end) = 4
and sum(case when f.fno = 5 then f.fval end) = 0 then 3
when sum(case when f.fno <= 3 then f.fval end) = 3
and sum(case when f.fno = 4 then f.fval end) = 0 then 4
when sum(case when f.fno <= 2 then f.fval end) = 2
and sum(case when f.fno = 3 then f.fval end) = 0 then 5
when sum(case when f.fno = 1 then f.fval end) = 1
and sum(case when f.fno = 2 then f.fval end) = 0 then 6
when sum(case when f.fno = 1 then f.fval end) = 0 then 7
end
from #tmp t
cross apply
(
values
(1, factor1),
(2, factor2),
(3, factor3),
(4, factor4),
(5, factor5),
(6, factor6)
) f (fno, fval)
group by t.client, t.[desirable_result]
order by t.client

You could try using CASE WHEN
select case
when [factor1] = 1
AND [factor2] = 1
AND [factor3] = 1
AND [factor4] = 1
AND [factor5] = 1
AND [factor6] = 1
then 'ALL6'
when [factor1] = 1
AND [factor2] = 1
AND [factor3] = 1
AND [factor4] = 1
AND [factor5] = 1
then 'FIRST5'
.....
....
when [factor1] = 1
AND [factor2] = 1
AND [factor3] = 1
AND [factor4] = 1
then 'FIRST4'
when [factor1] = 1
then 'ONLy1' END client_rate
from my_table
chenge the dot.... with the missing conditions

Related

T-SQL script produces wrong calculation [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
Improve this question
The script below has an issue when it encounter division or averages etc. I would like to produce a result in the screen shot below but there is an "N/A" value in the column which messes up the counts, sums, averages etc. If I exclude the count of N/A then it returns zero 0 which messes up the averages. It incorrectly calculates as there should be 17 rows and and there are 7 5's in the result set as you can see from the Calculations arrow so the division of 7/17 which should be equal to 0.411764 but it's 0.388889. Any ideas?
Create Table Test
(
Q4 NVARCHAR(255),
Q5 NVARCHAR(255)
);
INSERT INTO Test
(
Q4,
Q5
)
VALUES ('Strongly Agree', 'Agree'),
('Neutral', 'Disagree'),
('Neutral', 'Agree'),
('Strongly Agree', 'Disagree'),
('Agree', 'Strongly Disagree'),
('Strongly Disagree', 'Agree'),
('Strongly Agree', 'Disagree'),
('Agree', 'N/A'), -- Calculation Issue here because of N/A
('Agree', 'Strongly Disagree');
WITH cte1 AS (
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rn,
CASE WHEN [Q4] = 'Strongly Agree' THEN 5
WHEN [Q4] = 'Agree' THEN 4
WHEN [Q4] = 'Neutral' THEN 3
WHEN [Q4] = 'Disagree' THEN 2
WHEN [Q4] = 'Strongly Disagree' THEN 1
--WHEN [Q4] = 'N/A' THEN NULL
--when nullif([Q4], 'N/A') IS NOT NULL THEN 1 ELSE 0
END AS TestQ4,
CASE WHEN [Q5] = 'Strongly Agree' THEN 5
WHEN [Q5] = 'Agree' THEN 4
WHEN [Q5] = 'Neutral' THEN 3
WHEN [Q5] = 'Disagree' THEN 2
WHEN [Q5] = 'Strongly Disagree' THEN 1
END AS TestQ5
FROM Test
--where [Q4] <> 'N/A'
),
RolledUp AS (
SELECT
rn,
TestQ4, -- Question 4
TestQ5, -- Question 5
grouping = GROUPING(TestQ4),
count = COUNT(*),
count2 = COUNT(TestQ4),
-- Question 4 as TestQ4
sum4 = SUM(TestQ4),
avg4 = AVG(TestQ4 * 1.0),
one4 = COUNT(CASE WHEN TestQ4 = 1 THEN 1 END),
onePct4 = COUNT(CASE WHEN TestQ4 = 1 THEN 1 END) * 1.0 / COUNT(*),
CountFourOf_Two = COUNT(CASE WHEN TestQ4 = 2 THEN 1 END),
onePct4CountFourOf_Two = COUNT(CASE WHEN TestQ4 = 2 THEN 1 END) * 1.0 / COUNT(*),
CountFourOfThree = COUNT(CASE WHEN TestQ4 = 3 THEN 1 END),
onePct4CountFourOfThree = COUNT(CASE WHEN TestQ4 = 3 THEN 1 END) * 1.0 / COUNT(*),
CountFourOfFour = COUNT(CASE WHEN TestQ4 = 4 THEN 1 END),
onePct4CountFourOfFour = COUNT(CASE WHEN TestQ4 = 4 THEN 1 END) * 1.0 / COUNT(*),
CountFourOfFive = COUNT(CASE WHEN TestQ4 = 5 THEN 1 END),
onePct4CountFourOfFive = COUNT(CASE WHEN TestQ4 = 5 THEN 1 END) * 1.0 / COUNT(*),
-- Question 5 as TestQ5
sum5 = SUM(TestQ5),
avg5 = AVG(TestQ5 * 1.0),
one5 = COUNT(CASE WHEN TestQ5 = 1 THEN 1 END),
onePct5 = COUNT(CASE WHEN TestQ5 = 1 THEN 1 END) * 1.0 / COUNT(*),
CountFiveOf_Two = COUNT(CASE WHEN TestQ5 = 2 THEN 1 END),
onePct5CountFiveOf_Two = COUNT(CASE WHEN TestQ5 = 2 THEN 1 END) * 1.0 / COUNT(*),
CountFiveOfThree = COUNT(CASE WHEN TestQ5 = 3 THEN 1 END),
onePct5CountFiveOfThree = COUNT(CASE WHEN TestQ5 = 3 THEN 1 END) * 1.0 / COUNT(*),
CountFiveOfFour = COUNT(CASE WHEN TestQ5 = 4 THEN 1 END),
onePct5CountFiveOfFour = COUNT(CASE WHEN TestQ5 = 4 THEN 1 END) * 1.0 / COUNT(*),
CountFiveOfFive = COUNT(CASE WHEN TestQ5 = 5 THEN 1 END),
onePct5CountFiveOfFive = COUNT(CASE WHEN TestQ4 = 5 THEN 1 END) * 1.0 / COUNT(*)
FROM cte1
GROUP BY GROUPING SETS(
(rn, TestQ4, TestQ5),
()
)
)
SELECT v.TestQ4, v.TestQ5
FROM RolledUp r
CROSS APPLY (
SELECT TestQ4,TestQ5, 0 AS ordering
WHERE grouping = 0
UNION ALL
SELECT value1,value2, ordering
FROM (VALUES
(NULL,NULL, 1),
(count2,COUNT, 2),
(sum4,sum5, 3),
(avg4,avg5, 4),
(one4,one5, 5),
(onePct4,onePct5, 6),
(CountFourOf_Two,CountFiveOf_Two, 7),
(onePct4CountFourOf_Two,onePct5CountFiveOf_Two, 8),
(CountFourOfThree, CountFiveOfThree, 9),
(onePct4CountFourOfThree,onePct5CountFiveOfThree, 10),
(CountFourOfFour,CountFiveOfFour, 11),
(onePct4CountFourOfFour,onePct5CountFiveOfFour, 12),
(CountFourOfFive,CountFiveOfFive,13),
(onePct4CountFourOfFive,onePct5CountFiveOfFive, 14)
) v(value1,value2, ordering)
WHERE grouping = 1
) v
ORDER BY ordering, rn;
Your onePct5CountFiveOfFive calculation is referencing the wrong question. That looks to be the cause of your current problem.
I changed the last calculations for both questions TestQ4, and TestQ5 like this and it worked.
onePct4CountFourOfFive = COUNT(CASE WHEN TestQ4 = 5 THEN 1 END) * 1.0 / NULLIF(COUNT(TestQ4),0)

Adding a dummy identifier to data that varies by position and value

I am working on a project in SQL Server with diagnosis codes and a patient can have up to 4 codes but not necessarily more than 1 and a patient cannot repeat a code more than once. However, codes can occur in any order. My goal is to be able to count how many times a Diagnosis code appears in total, as well as how often it appears in a set position.
My data currently resembles the following:
PtKey
Order #
Order Date
Diagnosis1
Diagnosis2
Diagnosis3
Diagnosis 4
345
1527
7/12/20
J44.9
R26.2
NULL
NULL
367
1679
7/12/20
R26.2
H27.2
G47.34
NULL
325
1700
7/12/20
G47.34
NULL
NULL
NULL
327
1710
7/12/20
I26.2
J44.9
G47.34
NULL
I would think the best approach would be to create a dummy column here that would match up the diagnosis by position. For example, Diagnosis 1 with A, and Diagnosis 2 with B, etc.
My current plan is to rollup the diagnosis using an unpivot:
UNPIVOT ( Diag for ColumnALL IN (Diagnosis1, Diagnosis2, Diagnosis3, Diagnosis4)) as unpvt
However, this still doesn’t provide a way to count the diagnoses by position on a sales order.
I want it to look like this:
Diagnosis
Total Count
Diag1 Count
Diag2 Count
Diag3 Count
Diag4 Count
J44.9
2
1
1
0
0
R26.2
1
1
0
0
0
H27.2
1
0
1
0
0
I26.2
1
1
0
0
0
G47.34
3
1
0
2
0
You can unpivot using apply and aggregate:
select v.diagnosis, count(*) as cnt,
sum(case when pos = 1 then 1 else 0 end) as pos_1,
sum(case when pos = 2 then 1 else 0 end) as pos_2,
sum(case when pos = 3 then 1 else 0 end) as pos_3,
sum(case when pos = 4 then 1 else 0 end) as pos_4
from data d cross apply
(values (diagnosis1, 1),
(diagnosis2, 2),
(diagnosis3, 3),
(diagnosis4, 4)
) v(diagnosis, pos)
where diagnosis is not null;
Another way is to use UNPIVOT to transform the columns into groupable entities:
SELECT Diagnosis, [Total Count] = COUNT(*),
[Diag1 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis1' THEN 1 ELSE 0 END),
[Diag2 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis2' THEN 1 ELSE 0 END),
[Diag3 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis3' THEN 1 ELSE 0 END),
[Diag4 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis4' THEN 1 ELSE 0 END)
FROM
(
SELECT * FROM #x UNPIVOT (Diagnosis FOR DiagGroup IN
([Diagnosis1],[Diagnosis2],[Diagnosis3],[Diagnosis4])) up
) AS x GROUP BY Diagnosis;
Example db<>fiddle
You can also manually unpivot via UNION before doing the conditional aggregation:
SELECT Diagnosis, COUNT(*) As Total Count
, SUM(CASE WHEN Position = 1 THEN 1 ELSE 0 END) As [Diag1 Count]
, SUM(CASE WHEN Position = 2 THEN 1 ELSE 0 END) As [Diag2 Count]
, SUM(CASE WHEN Position = 3 THEN 1 ELSE 0 END) As [Diag3 Count]
, SUM(CASE WHEN Position = 4 THEN 1 ELSE 0 END) As [Diag4 Count]
FROM
(
SELECT PtKey, Diagnosis1 As Diagnosis, 1 As Position
FROM [MyTable]
UNION ALL
SELECT PtKey, Diagnosis2 As Diagnosis, 2 As Position
FROM [MyTable]
WHERE Diagnosis2 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis3 As Diagnosis, 3 As Position
FROM [MyTable]
WHERE Diagnosis3 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis4 As Diagnosis, 4 As Position
FROM [MyTable]
WHERE Diagnosis4 IS NOT NULL
) d
GROUP BY Diagnosis
Borrowing Aaron's fiddle, to avoid needing to rebuild the schema from scratch, and we get this:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d1f7f525e175f0f066dd1749c49cc46d

3 Query by column and create a new table

I have students, and these students have their meals, morning and evening. I want to print the number of meals each student eats in the morning and evening.
If the number of dishes that student eats in the morning is more than one, I want to print the number in the table and the ID of the food.
FoodType when 1(morning), and when 2(evening)
StudentId FoodId FoodType
3 1 1
3 2 1
3 3 1
3 4 2
4 3 1
4 1 2
4 2 2
4 4 2
5 4 2
5 1 1
6 1 1
6 2 1
6 3 2
6 4 2
Sample out;
StudentId MorningFoodCountOrId EveningFoodCountOrId
3 3 meals 4
4 3 3 meals
5 4 1
6 2 meals 2 meals
Use conditional aggregation. The logic that decides if we print the number of records or their value is not intuitive, but I would phrase it as follows:
select
studentId,
case when sum(case when foodtype = 1 then 1 else 0 end) = 1
then max(case when foodtype = 1 then foodId end)
else sum(case when foodtype = 1 then 1 else 0 end)
end MorningFoodCountOrId
case when sum(case when foodtype = 2 then 1 else 0 end) = 1
then max(case when foodtype = 2 then foodId end)
else sum(case when foodtype = 2 then 1 else 0 end)
end EveningFoodCountOrId
from mytable
group by studentId
You RDMBS should be able to optimize the query by not computing the conditional sums twice.
Note: you did not specify which RDMBS you are using. If this is MySQL, then it is possible to shorten the conditional sums a little, as follows:
select
studentId,
case when sum(foodtype = 1) = 1
then max(case when foodtype = 1 then foodId end)
else sum(foodtype = 1)
MorningFoodCountOrId
case when sum(foodtype = 2) = 1
then max(case when foodtype = 2 then foodId end)
else sum(foodtype = 2)
EveningFoodCountOrId
from mytable
group by studentId
Here's your query, select sum() and case.. will do this
select t1.studentid
, case when t1.m <= 1 then t2.FoodId else concat(t1.m, ' meals') end MorningFoodCountOrId
, case when t1.e <= 1 then t3.FoodId else concat(t1.e, ' meals') end EveningFoodCountOrId
from(
select studentid
, sum(case when FoodType = 1 then 1 else 0 end) as m
, sum(case when FoodType = 2 then 1 else 0 end) as e
from tableA
group by studentid) t1
left join tableA t2 on t2.studentId = t1.studentId and t1.m = 1 and t2.FoodType = 1
left join tableA t3 on t3.studentId = t1.studentId and t1.e = 1 and t3.FoodType = 2
order by t1.studentid
see dbfiddle
in postgresql
, case when t1.m <= 1 then t2.FoodId::text else concat(t1.m, ' meals') end MorningFoodCountOrId
, case when t1.e <= 1 then t3.FoodId::text else concat(t1.e, ' meals') end EveningFoodCountOrId

group by and select max with value null

I have a next problem with query
SELECT
T.DETALLE_BECA_ANIO anio,
T.DETALLE_BECA_MES mes,
T.DETALLE_BECA_NIVEL_EDU_ID edu_id,
T.DETALLE_BECA_TRAMO_ID tr_id,
MAX(
CASE
WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) mant ,
MAX(
CASE
WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM
(SELECT DETALLE_BECA_NIVEL_EDU_ID,
DETALLE_BECA_BECA_ID,
DETALLE_BECA_TIPO_BENE_ID,
DETALLE_BECA_VALOR,
DETALLE_BECA_MES,
DETALLE_BECA_REGION_ID,
DETALLE_BECA_PROVINCIA_ID,
DETALLE_BECA_ANIO,
DETALLE_BECA_TRAMO_ID,
DETALLE_BECA_COMUNA_ID
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1
OR DETALLE_BECA_TIPO_BENE_ID IS NULL)
and DETALLE_BECA_BECA_ID = 1
and detalle_beca_mes = 3
) T
GROUP BY T.DETALLE_BECA_BECA_ID,
T.DETALLE_BECA_TRAMO_ID,
T.DETALLE_BECA_REGION_ID,
T.DETALLE_BECA_PROVINCIA_ID,
T.DETALLE_BECA_ANIO,
T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID,
T.DETALLE_BECA_COMUNA_ID
ORDER BY T.DETALLE_BECA_BECA_ID,
T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID
output:
"ANIO" "MES" "EDU_ID" "TR_ID" "MANT" "TRAS"
2017 3 2 0.62 0 NULL
2017 3 3 1.24 6 NULL
2017 3 NULL 1.0 NULL 1
I need that sum value where EDU_ID is null with value 2,3 in TR_ID and replace value null in "tras" with value from EDU is null
"ANIO" "MES" "EDU_ID" "TR_ID" "MANT" "TRAS"
2017 3 2 1.62 0 1
2017 3 3 2.24 6 1
I writed query with min(edu_id) or max(edu_id ) but could not solve my problem.
The other thing that occurred to me is to make a join with the same table
First, this makes more sense as your query:
SELECT T.DETALLE_BECA_ANIO as anio, T.DETALLE_BECA_MES as mes,
T.DETALLE_BECA_NIVEL_EDU_ID as edu_id, T.DETALLE_BECA_TRAMO_ID as tr_id,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR, 0)
ELSE 0
END) as mant ,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1 OR DETALLE_BECA_TIPO_BENE_ID IS NULL) AND
DETALLE_BECA_BECA_ID = 1 AND
detalle_beca_mes = 3
GROUP BY T.DETALLE_BECA_ANIO, T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID, T.DETALLE_BECA_TRAMO_ID
ORDER BY T.DETALLE_BECA_BECA_ID, T.DETALLE_BECA_MES, T.DETALLE_BECA_NIVEL_EDU_ID;
This eliminates the subquery (unnecessary) and only aggregates by the columns being returned. A proper query might fix your problem.
But, you seem to want to use NULL to be "all" for the other columns. If so, something like this will work:
WITH t as (
SELECT T.DETALLE_BECA_ANIO as anio, T.DETALLE_BECA_MES as mes,
T.DETALLE_BECA_NIVEL_EDU_ID as edu_id, T.DETALLE_BECA_TRAMO_ID as tr_id,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID IS NULL
THEN NVL(DETALLE_BECA_VALOR, 0)
ELSE 0
END) as mant ,
MAX(CASE WHEN T.DETALLE_BECA_TIPO_BENE_ID = 1
THEN NVL(DETALLE_BECA_VALOR,0)
ELSE 0
END) tras
FROM TBL_DETALLE_BECAS
WHERE (DETALLE_BECA_TIPO_BENE_ID = 1 OR DETALLE_BECA_TIPO_BENE_ID IS NULL) AND
DETALLE_BECA_BECA_ID = 1 AND
detalle_beca_mes = 3
GROUP BY T.DETALLE_BECA_ANIO, T.DETALLE_BECA_MES,
T.DETALLE_BECA_NIVEL_EDU_ID, T.DETALLE_BECA_TRAMO_ID
)
SELECT t.ANIO, t.MES, t.EDU_ID,
COALESCE(t.TR_ID, 0) + COALESCE(tnull.TR_ID, 0) as TR_ID,
t.MANT,
COALESCE(t.TRAS, 0) + COALESCE(tnull.TRAS, 0) as TRAS
FROM t LEFT JOIN
(SELECT t.*
FROM t
WHERE t.edu_id IS NULL
) tnull
ON tnull.ANIO = t.ANIO AND tnull.MES = t.MES
WHERE t.edu_id IS NOT NULL
ORDER BY T.DETALLE_BECA_BECA_ID, T.DETALLE_BECA_MES, T.DETALLE_BECA_NIVEL_EDU_ID;

SQL Server: Using COUNT with IN and NOT IN

I have a data table as follows :
file_id | action code
1 | 10
1 | 20
2 | 10
2 | 12
3 | 10
3 | 20
4 | 10
4 | 10
4 | 20
The output is:
file_id | Warning
1 | 0
2 | 0 <- this should be 1 instead
3 | 0
4 | 1
The first count works as expected, and sets warning as 1, if there are any action_code duplicates, but i can't get it to work and display a warning if action_code is not perfectly divisible with 10
#exported [int] = NULL,
#bin_id [int] = NULL,
#date_start [DateTime],
#date_stop [DateTime],
#action_code [int] = NULL,
#action_description [varchar](43) = NULL
SELECT
dbo.Tf.file_id AS 'ID',
dbo.Tf.file_name AS 'NAME',
MAX(dbo.TFD.action_date) AS 'DATE',
MAX(dbo.TFD.file_length) AS 'SIZE',
dbo.Bins.name AS 'BIN',
dbo.TFD.action_description,
CASE
WHEN (COUNT(DISTINCT dbo.TFD.action_code) <> COUNT(dbo.TFD.action_code) )
AND
((SELECT COUNT ( dbo.TFD.action_code ) FROM TFD WHERE action_code IN (10,20,30,40,50)) > 0
AND
(SELECT COUNT ( dbo.TFD.action_code ) FROM TFD WHERE action_code NOT IN (10,20,30,40,50)) > 0 ) THEN 1
ELSE 0
END AS 'Warning'
FROM
( SELECT
dbo.Tf.file_id,
MAX(dbo.TFD.action_code) AS 'action_code'
FROM Tf
INNER JOIN TFD
ON Tf.file_id = TFD.file_id INNER JOIN Bins ON Tf.bin_id = Bins.bin_id
WHERE
(#bin_id IS NULL OR Tf.bin_id = #bin_id)
AND Tf.file_id IN
(
SELECT H.file_id
FROM Tf AS H INNER JOIN TFD AS D ON H.file_id = D.file_id
WHERE ((D.action_date >= #date_start AND D.action_date <= #date_stop) OR (H.file_date >= #date_start AND H.file_date <= #date_stop))
AND (H.bin_id = #bin_id OR #bin_id IS NULL)
AND H.file_type = #exported
AND ((#action_description IS NULL) OR (D.action_description LIKE #action_description + '%'))
)
AND (#exported IS NULL OR Tf.file_type = #exported)
GROUP BY dbo.Tf.file_id) AS TempSelect
INNER JOIN Tf
ON Tf.file_id = TempSelect.file_id
INNER JOIN TFD
ON (TFD.file_id = TempSelect.file_id
AND TFD.action_code = TempSelect.action_code)
INNER JOIN Bins ON Tf.bin_id = Bins.bin_id
WHERE
(
(#action_code IS NULL ) OR (#action_code <> -1 AND TempSelect.action_code = #action_code)
OR (#action_code = -1 AND TempSelect.action_code NOT IN (10,20,30,40) )
)
GROUP BY
dbo.Tf.file_id,
dbo.Tf.file_name,
dbo.Bins.name,
dbo.Tf.bin_id,
dbo.TFD.action_description
EDIT: I added the whole procedure. My main goal,among others, is to set the field warning as 1 if the following conditions are met:
if there are any action_code duplicates (as it's the case for file 4)
if there is an action_code not divisible by 10 among the other action_codes for each file (as it's the case with file 2)
If your logic is: Set a flag to 1 if there are duplicates or if a code is not divisible by 10, then I would suggest:
select (case when count(distinct d.action_code) <> count(*) then 1
else max(case when d.action_code % 10 <> 0 then 1 else 0 end)
end)
Notice that I replaced dbo.Detail with the table alias d. Table aliases make a query easier to write, read, and understand.
Hope this helps you:
SELECT FILE_ID,
MAX(CASE WHEN action_code % 10 != 0 THEN 1 END) not_divisible,
CASE WHEN COUNT(*)!=COUNT(DISTINCT action_Code) THEN 1 END not_unique
FROM #test
GROUP BY FILE_ID
Putting it all together you can use:
SELECT file_id,
CASE WHEN COUNT(*)!=COUNT(DISTINCT action_Code) THEN 1
ELSE MAX(CASE WHEN action_code % 10 != 0 THEN 1 ELSE 0 END) END Warning
FROM #test
GROUP BY file_id
Try with the below query..
CREATE TABLE #t (FileID INT,ActionCode INT)
INSERT INTO #t
VALUES (1,10),(1,20),(2,10),(2,12),(3,10),(3,20),(4,10),(4,10),(4,20)
WITH cte_1
as (
SELECT *,COUNT(1) OVER(PARTITION BY FileID,ActionCode ORDER BY fileID,ActionCode) CNT
FROM #T)
SELECT FileID,case WHEN SUM(ActionCode) %10 <>0 THEN 1 WHEN MAX(CNT)<>1 THEN 1 ELSE 0 END
FROM CTE_1
GROUP BY FileID
Result :
Thanks all for your answers, they were helpful, i modified the following section as such, and now it works:
...
dbo.TFD.action_description,
CASE
WHEN (COUNT(DISTINCT dbo.TFD.action_code) <> COUNT(dbo.TFD.action_code)) OR err_ac > 0
THEN 1 ELSE 0 END AS 'Warning'
FROM
(
SELECT
dbo.Tf.file_id,
MAX(dbo.TFD.action_code) AS 'action_code',
CASE
WHEN SUM(dbo.TFD.action_code) %10 <> 0 THEN 1 ELSE 0 END AS 'err_ac'
...