Summing By Count - sql

I'm trying to create a Summation based on the Count number for a particular column. If you looks at the last line in the Select below you'll see that I tried implementing a CASE statement. However, it produces all NULL values. Which I believe I understand why (each row has a unique set of values) but I'm not sure how to fix my problem.
SELECT
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed TotalIndexed,
TotalFilesProduced.FileNumberofPages TotalFileNumberofPages,
TotalFilesProduced.FilesProduced,
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1 THEN SUM(TotalFilesProduced.FilesIndexed) END
FROM
(SELECT
CAST(ibfp.FileReviewedDate AS DATE) ReviewDate,
ibfp.FileReviewedByUserID,
FileSource,
COUNT(*) FilesProduced,
COUNT(DISTINCT ibf.InboundFileID) FilesIndexed,
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
FROM
dbo.InboundFilePartitions ibfp
INNER JOIN dbo.InboundFiles ibf ON ibfp.InboundFileID = ibf.InboundFileID
WHERE
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
and ibf.ProjectID in (110)
GROUP BY
CAST(ibfp.FileReviewedDate AS DATE),
ibfp.FileReviewedByUserID,
FileSource
) TotalFilesProduced
GROUP BY
TotalFilesProduced.ReviewDate,
TotalFilesProduced.FileReviewedByUserID,
TotalFilesProduced.FileSource,
TotalFilesProduced.FilesIndexed,
TotalFilesProduced.FileNumberofPages,
TotalFilesProduced.FilesProduced
Here is an example for further clarification - here the UserID 1036 producing a NULL is fine since it appear only once but for 804 - I would like to sum the TotalIndexed column so the NULL area should read 139 (for both instances that 804 appears)
ReviewDate | FilereviewedByUserID | FileSource | TotalIndexed | TotalFileNumberofPages | FilesProduced | (No Column Name) /*My Sum*/
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 1 | 1 | 67 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 1036 | 1 | 1 | 17 | 1 | NULL
------------------------------------------------------------------------------------------------------------------------------------
2014-10-22 | 804 | 2 | 138 | 3322 | 184 | NULL

As stated in the comment
This will always be false
CASE WHEN COUNT(DISTINCT FileReviewedByUserID) > 1
Because of
GROUP BY ibfp.FileReviewedByUserID
And you have some other strange stuff
CAST(ibfp.FileReviewedDate AS DATE) >= '10/22/2014'
and CAST(ibfp.FileReviewedDate AS DATE) <= '10/22/2014'
is the same as
CAST(ibfp.FileReviewedDate AS DATE) = '10/22/2014'
More strange stuff
SUM(CASE WHEN ibfp.FromPage = ibfp.ToPage THEN 1
ELSE ibfp.ToPage-ibfp.FromPage + 1 END) [FileNumberofPages]
is the same as
SUM(ibfp.ToPage-ibfp.FromPage + 1) [FileNumberofPages]
not sure what you are trying to do but a group by on a group by is not common

Related

Calculate data in Pivot

I have the following SQL table with 4 columns.
Table Name: tblTimeTransaction
Columns: EmployeeNumber, TransactionDate, CodeType, TimeShowninSeconds
CodeType has values : REG, OT1, OT2, OT3 respectively
I want it to show like this using pivot using 15 days incrementals starting from Jan 1 2020 onwards:
Employee Number | Effective Date | REG | OT1 | OT2 | OT3
E12345 | Between 10-1 till 10-15 | 200 | 100 | 50 | 45
E15000 | Between 10-1 till 10-15 | 400 | 600 | 903 | 49
E12345 | Between 10-15 till 10-31 | 200 | 100 | 50 | 45
E15000 | Between 10-15 till 10-31 | 400 | 600 | 903 | 49
E12346 | Between 11-1 till 11-15 | 4200 | 100 | 50 | 45
E15660 | Between 11-1 till 11-15 | 1200 | 600 | 6903 | 49
My SQL Code so far:
SELECT
Employee Number,
[TransactionDate] as [Effective Date],
[REG],
[OT1],
[OT2],
[OT3]
FROM
( SELECT Employee Number, TransactionDate, CodeType, TimeInSeconds
FROM [tblTimetransaction]
) ps
PIVOT
( SUM (TimeInSeconds)
FOR CodeType IN ( [REG], [OT1], [OT2], [OT3])
) AS pvt
where TransactionDate between '2020-01-01' and '2020-12-31'
If I follow you correctly, you can truncate the effective_date to either the 1st of 15th of the month depending on their day of the month, then use conditional aggregation to compute the total time_in_seconds for each code_type:
select employee_number,
datefromparts(year(effective_date), month(effective_date), case when day(effective_date) < 15 then 1 else 15 end) as dt,
sum(case when code_type = 'REG' then time_in_seconds else 0 end) as reg,
sum(case when code_type = 'OT1' then time_in_seconds else 0 end) as ot1,
sum(case when code_type = 'OT2' then time_in_seconds else 0 end) as ot2,
sum(case when code_type = 'OT3' then time_in_seconds else 0 end) as ot3
from tblTimetransaction
where effective_date >= '20200101' and effective_date < '20210101'
group by employee_number,
datefromparts(year(effective_date), month(effective_date), case when day(effective_date) < 15 then 1 else 15 end)

SQL logic to determine unsold inventory and corresponding available dates (Available to sell)

I am looking for advice on how to generate SQL to be used in SQL Server that will show available inventory to sell and the corresponding date that said inventory will be available. I am easily able to determine if we have inventory that is available immediately but can't wrap my head around what logic would be needed to determine future available quantities.
In the below table. The +/- column represents the weekly inbound vs outbound and the quantity available is a rolling SUM OVER PARTITION BY of the +/- column. I was able to get the immediate quantity available through this simple logic:
Case when Min(X.Qty_Available) > 0 Then Min(X.Qty_Available) else 0 END
AS Immediate_available_Qty
Table:
+-------------+---------------+---------------+------+---------------+
| Item Number | Item Name | week_end_date | +/- | Qty_Available |
+-------------+---------------+---------------+------+---------------+
| 123456 | Fidget Widget | 7/13/2019 | 117 | 117 |
| 123456 | Fidget Widget | 7/20/2019 | 49 | 166 |
| 123456 | Fidget Widget | 7/27/2019 | -7 | 159 |
| 123456 | Fidget Widget | 8/3/2019 | -12 | 147 |
| 123456 | Fidget Widget | 8/10/2019 | -1 | 146 |
| 123456 | Fidget Widget | 8/17/2019 | 45 | 191 |
| 123456 | Fidget Widget | 8/24/2019 | -1 | 190 |
| 123456 | Fidget Widget | 8/31/2019 | -1 | 189 |
| 123456 | Fidget Widget | 9/7/2019 | 50 | 239 |
+-------------+---------------+---------------+------+---------------+
My desired results of this query would be as follows:
+-----------+-----+
| Output | Qty |
+-----------+-----+
| 7/13/2019 | 117 |
| 7/20/2019 | 29 |
| 8/17/2019 | 43 |
+-----------+-----+
the second availability is determined by taking the first available quantity of 117 out of each line in Qty_Available column and finding the new minimum. If the new min is Zero, find the next continuously positive string of data (that runs all the way to the end of the data). Repeat for the third_available quantity and then stop.
I was on the thought train of pursuing RCTE logic but don't want to dive into that rabbit hole if there is a better way to tackle this issue and I'm not even sure the RCTE work for this problem?
This should return your expected result:
SELECT Item_Number, Min(week_end_date), Sum("+/-")
FROM
(
SELECT *
-- put a positive value plus all following negative values in the same group
-- using a Cumulative Sum over 0/1
,Sum(CASE WHEN "+/-" > 0 THEN 1 ELSE 0 end)
Over (PARTITION BY Item_Number
ORDER BY week_end_date
ROWS UNBOUNDED PRECEDING) AS grp
FROM my_table
) AS dt
WHERE grp <= 3 -- only the 1st 3 groups
GROUP BY Item_Number, grp
So here's what I came up with. I know this is poor, I didn't want to leave this thread high and dry and maybe I can get more insight on a better path. Please know that I've never had any real training so I don't know what I don't know.
I ended up running this into a temp table and altering the commented out section in table "A". then re-running that into a temp table.
Select
F.Upc,
F.name,
F.Week_end_date as First_Available_Date,
E.Qty_Available_1
From
(
Select Distinct
D.Upc,
D.name,
Case When Min(D.Rolling_Qty_Available) Over ( PARTITION BY D.upc) < 1 then 0 else
Min(D.Rolling_Qty_Available) Over ( PARTITION BY D.upc) END as Qty_Available_1,
Case When Max(D.Look_up_Ref) Over ( PARTITION BY D.upc) = 0 then '-1000' else
Max(D.Look_up_Ref) Over ( PARTITION BY D.upc) END as Look_up_Ref_1
From
(
Select
A.Upc,
A.name,
A.Week_end_Date,
A.Rolling_Qty_Available,
CASE WHEN
C.Max_Row = A.Row_num and A.[Rolling_Qty_Available] >1 THEN 1
ELSE
CASE WHEN
Sum(A.Calc_Row_Thing) OVER (Partition by A.UPC Order by A.Row_Num DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND Current ROW
) = (C.Max_Row - A.Row_num + 1)
THEN
C.Max_Row - A.Row_num + 1
ELSE 0 END
END as Look_up_Ref
FROM (
Select
G.Upc,
G.Name,
G.Week_End_Date,
G.Row_num,
G.Calc_Row_Thing,
G.Rolling_Qty_Available
--CASE When (G.Rolling_Qty_Available -
--isnull(H.Qty_Available_1,0)) > 0 then 1 else - 0 END as
--Calc_Row_Thing,
From [dbo].[ATS_item_detail_USA_vw] as G
--Left Join [dbo].[tmp_ats_usa_qty_1] as H on G.upc = H.upc
) AS A --Need to subtract QTY 1 out of here and below
join (
SELECT
B.upc,
Max(Row_num) AS Max_Row
FROM [dbo].[ATS_item_detail_USA_vw] AS B
GROUP BY B.upc
) as C on A.upc = C.upc
) as D
GROUP BY
D.Upc,
D.name,
D.Rolling_Qty_Available,
D.Look_up_Ref
HAVING Max(D.Look_up_Ref) > 1
) as E
Left join
(
SELECT
A.Upc,
A.name,
A.Week_end_Date,
A.Rolling_Qty_Available,
CASE WHEN
C.Max_Row = A.Row_num and A.[Rolling_Qty_Available] >1 THEN 1
ELSE
CASE WHEN
Sum(A.Calc_Row_Thing) OVER (Partition by A.UPC Order by A.Row_Num DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND Current ROW
) = (C.Max_Row - A.Row_num + 1)
THEN
C.Max_Row - A.Row_num + 1
ELSE 0 END
END as Look_up_Ref
From (
Select
G.Upc,
G.Name,
G.Week_End_Date,
G.Row_num,
G.Calc_Row_Thing,
G.Rolling_Qty_Available
--CASE When (G.Rolling_Qty_Available -
--isnull(H.Qty_Available_1,0)) > 0 then 1 else - 0 END as
--Calc_Row_Thing,
From [dbo].[ATS_item_detail_USA_vw] as G
--Left Join [dbo].[tmp_ats_usa_qty_1] as H on G.upc = H.upc
) as A --subtract qty_1 out the start qty 2 calc
join (
SELECT
B.upc,
Max(Row_num) as Max_Row
FROM [dbo].[ATS_item_detail_USA_vw] as B
GROUP BY B.upc
) AS C ON A.upc = C.upc
) AS F ON E.upc = F.upc and E.Look_up_Ref_1 = F.Look_up_Ref

SQL Server - Return correct column 1 value based on check of column 2 value(s)

Data:
| id | Year | CPT | RVU | MOD |
+----+-------------+--------+-------+-----+
| 1 | 2015 | 99212 | 12 | 26 |
| 2 | 2015 | 99212 | 23 | TC |
| 3 | 2015 | 99212 | 56 | |
| 4 | 2015 | 99213 | 59 | 53 |
| 5 | 2015 | 99214 | 60 | |
| 6 | 2015 | 99215 | 99 | 53 |
| 7 | 2015 | 99216 | 78 | |
Output :
Return RVU = 12 for CPT 99212
Return RVU = 59 for CPT 99213
Return RVU = 60 for CPT 99214
Return RVU = 99 for CPT 99215
A CPT can have a MOD of 26, TC, 53, or NULL. My SQL needs to check for 26 first and if there is a 26 then return the RVU for that row, if not 26 then whatever else is left.
Worded differently: If a CPT does not have a MOD 26, then that CPT will only have one possible other MOD to choose from. If a CPT has a MOD 26 it will always have an accompanying TC and NULL MOD. If the CPT does not have a 26 MOD then I need to grab whatever RVU value is available regardless of the MOD. So the order of operations is to check for 26 first and if there, return RVU for that row, if no 26 then return the only possible RVU choice for that CPT.
You can use row_number() function with conditional ordering :
select top (1) with ties *
from table t
order by row_number() over (partition by cpt
order by (case when mod = '26' then 0 else 1 end)
);
Use row_number(). I think the prioritization is as follows:
select t.*
from (select t.*,
row_number() over (partition by cpt
order by (case mod when '26' then 1 when 2 end)
) as seqnum
from t
) t
where seqnum = 1;
You could do a self-join to get CPTs with a 26 mod in a separate virtual table.
Sample data creation:
declare #Data table
( id int identity
,[year] int default 2015
,CPT nchar(5)
,RVU nchar(2)
,[MOD] nchar(2)
)
insert into #Data
(CPT, RVU, [MOD])
values
('99212', '12', '26'),
('99212', '23', 'TC'),
('99212', '56', null),
('99213', '59', '53'),
('99214', '60', null),
('99215', '99', '53'),
('99216', '78', null)
Query:
select
Data.CPT
,case
when Is26.CPT is not null then Is26.RVU
else Data.RVU
end RVU
from #Data Data
left join #Data Is26 on
Is26.CPT = Data.CPT
and Is26.[MOD] = '26'
group by
Data.CPT
,case
when Is26.CPT is not null then Is26.RVU
else Data.RVU
end

How can i write this query more efficiently?

This Query works in a loop and thus its performance is too slow.
FUID is provided by a while loop.
SELECT (SELECT TOP 1 AmountPaid
from [xyz].[dbo].AmountReceived
WHERE C.IID = [xyz].[dbo].AmountReceived.IID
order by ReceivingDate asc)
FROM [xyz].[dbo].Customer C
Where C.BuisnessDate >= DATEADD(m,DATEDIFF(m,0,'2015-03-31'),0)
AND C.BuisnessDate <= DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2015-03-31')+1,0)) AND C.FUID=16
AND DATEDIFF(M,C.RiskDate,'2015-03-31') <=3
Customer table contains these related columns:
+------------+----+----------+----------+
| IID | FUID |BusinessDate|RiskDate |
+--------+------+------------+----------+
| 22433 | 13 |2013-05-02 |2007-05-23|
| 22443 | 26 |2014-02-18 |2011-09-07|
| 22906 | 32 |2014-12-22 |2015-01-12|
AmountReceived table:
+--------+---------------+-------------+
| IID |AmountPaid |ReceivingDate|
+--------+---------------+-------------+
| 22433 | 13800 |2015-02-02 |
| 22443 | 1290 |2014-12-18 |
| 22906 | 408 |2014-10-22 |
If I understand your question and you only get FUID in your WHILE, you need something like this
;WITH CTE AS
(
SELECT C.FUID,AR.AmountPaid,
ROW_NUMBER()OVER(PARTITION BY C.FUID ORDER BY AR.ReceivingDate ASC) rn
FROM [xyz].[dbo].Customer C
INNER JOIN [xyz].[dbo].AmountReceived AR
ON C.IID = AR.IID
WHERE C.BuisnessDate >= DATEADD(m,DATEDIFF(m,0,'2015-03-31'),0)
AND C.BuisnessDate <= DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2015-03-31')+1,0))
AND C.FUID BETWEEN 1 AND 47
AND C.RiskDate >= '2014-12-01'
)
SELECT C.FUID,AR.AmountPaid
FROM CTE
WHERE rn = 1
Also added the suggestion by thepirat000 in comments above to change DATEDIFF(M,C.RiskDate,'2015-03-31') <=3 to C.RiskDate >= '2014-12-01'

filter by Sum without Grouping

i have a resultset that i generate from a query that Looks like this:
Select Employee, Month, (select case when Status = '---' then 0 Else 1 end) as PlaningValue
From PlanningTable PT
Where Month >= #From Month and Month <= #ToMonth
The Result of this Looks something like this:
|Employee| Month | PlaningValue |
|George | 2014-01 | 1 |
|George | 2014-02 | 1 |
|George | 2014-03 | 0 |
|Andrew | 2014-01 | 0 |
|Andrew | 2014-02 | 1 |
|Andrew | 2014-03 | 0 |
|Howard | 2014-01 | 1 |
|Howard | 2014-02 | 1 |
|Howard | 2014-03 | 1 |
Now what i want is the following:
Filter out Employee's who, over the three month period, have a total planing Value of 3,
in the example above, Howard would be filtered out.
Is there a way to do this nicely or is it all just impossible to even thin ?
(Remark: Since i am going to use the Query on Reporting Services, i can't use the OVER function)
Thank you all for your help
This looks to be SQL Server syntax, as such I you can use windowed functions:
WITH CTE AS
( SELECT Employee,
Month,
PlanningValue = CASE WHEN Status = '---' THEN 0 ELSE 1 END,
Total = SUM(CASE WHEN Status = '---' THEN 0 ELSE 1 END)
OVER (PARTITION BY Employee)
FROM PlanningTable
WHERE Month >= #FromDate
AND Month <= #ToMonth
)
SELECT Employee, Month, PlanningValue
FROM CTE
WHERE Total != 3;
Simplified Example on SQL Fiddle
Try:
select pt.employee, pt.month, pt.planningvalue
from planningtable pt
join planningtable pt2 on pt.employee = pt2.employee
join planningtable pt3 on pt.employee = pt3.employee
join planningtable pt4 on pt.employee = pt4.employee
where month >= #mofrom and month <= #tomonth
and pt2.month = #tomonth
and pt3.month in (select month from planningtable where month > #mofrom and month < #tomonth)
and pt4.month = #mofrom
and pt2.planningvalue + pt3.planningvalue + pt4.planningvalue <> 3