I have the following query:
SELECT TOP 500
BusinessDate,
BRANCH_CO_MNE,
RIGHT(TRANS_INPUTTER, 5) 'USER_ID',
CASE
WHEN TRANS_TYPE LIKE '%Deposit%'
THEN COUNT(*)
END 'No of Cash Deposit'
FROM test_link.MMBL_phase2.dbo.EB_MMBL_H_UAR_PROT
WHERE BusinessDate = '2023-01-23'
GROUP BY BusinessDate,
BRANCH_CO_MNE,
TRANS_INPUTTER,
TRANS_TYPE
ORDER BY USER_ID
Which returns the following results:
BusinessDate
BRANCH_CO_MNE
USER_ID
No of Cash Deposit
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
11748
NULL
2023-01-23
BNK
11748
NULL
2023-01-23
BNK
11748
NULL
2023-01-23
BNK
11748
NULL
2023-01-23
BNK
11748
NULL
2023-01-23
BNK
11748
18
2023-01-23
BNK
11748
NULL
The NULL values are repeating while I have put the No of Cash Deposit in GROUP BY clause.
Shouldn't the results be like
BusinessDate
BRANCH_CO_MNE
USER_ID
No of Cash Deposit
2023-01-23
BNK
10938
NULL
2023-01-23
BNK
11748
18
2023-01-23
BNK
11748
NULL
I suspect the problem here is your attempt at conditional aggregation. For conditional aggregation the aggregation function doesn't go inside the CASE expression, the CASE expression is put inside the aggregate function. As a result of your method, you have to GROUP BY the column TRANS_INPUTTER because it's not being aggregated.
If you switch to conditional aggregation, then you can remove TRANS_TYPE from the GROUP BY. Also, you then need to change the GROUP BY on TRANS_INPUTTER to be RIGHT(TRANS_INPUTTER, 5).
SELECT TOP (500)
BusinessDate,
BRANCH_CO_MNE,
RIGHT(TRANS_INPUTTER, 5) AS USER_ID,
COUNT(CASE WHEN TRANS_TYPE LIKE '%Deposit%' THEN 1 END) AS [No of Cash Deposit]
FROM test_link.MMBL_phase2.dbo.EB_MMBL_H_UAR_PROT
WHERE BusinessDate = '2023-01-23'
GROUP BY BusinessDate,
BRANCH_CO_MNE,
RIGHT(TRANS_INPUTTER, 5)
ORDER BY USER_ID;
You are also grouping on TRANS_INPUTTER and TRANS_TYPE. When those values are different, you will have also rows for those even if you don't specify them in your SELECT statement.
However as we don't have scripts for testdata I cannot reproduce your problem for now.
SELECT TOP 500
BusinessDate,
BRANCH_CO_MNE,
RIGHT(TRANS_INPUTTER, 5) 'USER_ID',
CASE
WHEN TRANS_TYPE LIKE '%Deposit%'
THEN COUNT(*)
END 'No of Cash Deposit'
FROM test_link.MMBL_phase2.dbo.EB_MMBL_H_UAR_PROT
WHERE BusinessDate = '2023-01-23'
GROUP BY BusinessDate,
BRANCH_CO_MNE,
RIGHT(TRANS_INPUTTER, 5),
CASE
WHEN TRANS_TYPE LIKE '%Deposit%'
THEN COUNT(*)
END
ORDER BY USER_ID
Related
I have a query that generates this table:
DateCompleted
GtrReference
SourceWarehouse
TargetWarehouse
DateCreated
EntryType
ControlAccount
InitialValue
Operator
FirstDesc
SecondDesc
202302
01062023
W
01
2023-01-06 00:00:00.000
W
1610
6080.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
202302
01172023
W
01
2023-01-17 00:00:00.000
W
1610
6210.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
202302
02022023
W
01
2023-02-02 00:00:00.000
W
1610
3616.00
CWHITE
IN TRANSIT WAREHOUSE
MAIN WAREHOUSE
The Query:
select
DateCompleted,
GtrReference,
SourceWarehouse,
TargetWarehouse,
DateCreated,
EntryType,
ControlAccount,
InitialValue,
Operator,
FirstDesc,
SecondDesc
from
(
select
concat(d.TransfCompYear, case when len(d.TransfCompPeriod) = 1 then '0' end, d.TransfCompPeriod) as DateCompleted,
a.Complete,
d.Line,
d.TransfCompPeriod as DateMonth,
d.TransfCompYear as DateYear,
a.GtrReference as GtrReference,
a.SourceWarehouse as SourceWarehouse,
max(a.TargetWarehouse) over (partition by a.GtrReference) as TargetWarehouse,
a.DateCreated as DateCreated,
COALESCE(d.ExpectedDueDate, d.ExpectedDueDate) as ExpectedDueDate,
a.EntryType as EntryType,
a.ControlAccount as ControlAccount,
max(a.InitialValue) over (partition by a.GtrReference) as InitialValue,
a.Operator as Operator,
b.Description as FirstDesc,
c.Description as SecondDesc
FROM
[GtrMaster] a
LEFT JOIN [InvWhControl] b
ON (a.SourceWarehouse = b.Warehouse)
LEFT JOIN [InvWhControl] c
ON (a.TargetWarehouse = c.Warehouse)
LEFT JOIN [GtrDetail] d
ON (a.GtrReference = d.GtrReference)
) as i
WHERE ( i.EntryType = 'W' OR i.EntryType = 'S' )
AND i.Complete = 'Y' AND i.GtrReference >= ''
and i.Line = '1'
and i.DateCompleted >= convert(varchar(6),getdate()-90,112)
ORDER BY i.DateCompleted desc
What i'm trying to do is change the DateCompleted column to show an actual date.
Ex, I want to change 202302 to show 2023-02-01, and 202301 to show 2023-01-01. How can I convert my current date column to that?
Use Convert:
Convert(DateTime, [DateCompleted] + '01') As TrueDateCompleted
The returned date values you can format as you like.
A calendar table would be very useful here.
From a calendar table you could CONCAT() the year and month columns for each date (or use a YearMonthNum column). Then join this column to your DateCompleted column, returning only the first date of each month via some distinction clause e.g., WHERE DayNum = 1
I have a dataset with 3 columns. Table name is #test. I want to create the 4th column ("Result") that satisfies some conditions. The terms are as follows:
Get if the first Resolved value of a contact is 0.
Get if the first value after 1 in the Resolved column is 0. If they continue as 0, do not include them.
These conditions must be applied separately for each contact.
I am sharing the example below.
Thank you.
I hope this can help :
DECLARE #TMP table (
ContactCode int,
HistoryDate date,
Resolved bit
)
INSERT INTO #TMP VALUES
(466, '2022-02-28',0),
(466, '2022-03-31',1),
(466, '2022-04-30',0),
(466, '2022-05-31',0),
(466, '2022-06-30',1),
(466, '2022-07-31',0),
(467, '2022-02-28',0),
(467, '2022-03-31',0),
(467, '2022-04-30',0),
(467, '2022-05-31',0),
(467, '2022-06-30',1),
(467, '2022-07-31',0)
SELECT
ContactCode,
HistoryDate,
Resolved,
CASE
WHEN
ROW_NUMBER() OVER(PARTITION BY ContactCode ORDER BY HistoryDate ASC) = 1
OR LAG(Resolved, 1, 0) OVER(PARTITION BY ContactCode ORDER BY HistoryDate ASC) = 1
THEN 0
ELSE NULL
END AS Result
FROM #TMP
Result :
ContactCode
HistoryDate
Resolved
Result
466
2022-02-28
0
0
466
2022-03-31
1
NULL
466
2022-04-30
0
0
466
2022-05-31
0
NULL
466
2022-06-30
1
NULL
466
2022-07-31
0
0
467
2022-02-28
0
0
467
2022-03-31
0
NULL
467
2022-04-30
0
NULL
467
2022-05-31
0
NULL
467
2022-06-30
1
NULL
467
2022-07-31
0
0
ROW_NUMBER() allows you to 'order' your data in a partition (here your partition is your ContactCode and order by HistoryDate). You then whant the first one (ROW_NUMBER() ... = 1)
LAG() will look for the previous value of Resolved, if it's a 1 you print 0for your current row.
I have this table :
ArretProductionJournee(Id, DateArret,HeureDebut,HeureFin,EnumArret)
Example :
DateArret ||HeureDebut ||HeureFin ||EnumArret
2020-11-30 ||2020-11-30 14:00:00.000 ||2020-11-30 15:00:00.000 ||PS
2020-11-30 ||2020-11-30 16:00:00.000 ||2020-11-30 17:00:00.000 ||HI
i want to sum the datediff(HeureDebut,HeureFin) in columns for each EnumArret
so i run this query :
SELECT ArretProductionJournee.DateArret,
(select
sum (datediff(minute,ArretProductionJournee.HeureDebut,
ArretProductionJournee.HeureFin))
where ArretProductionJournee.EnumArret Like 'HI')as HI,
(select
sum (datediff(minute,ArretProductionJournee.HeureDebut,
ArretProductionJournee.HeureFin))
where ArretProductionJournee.EnumArret Like 'PS') as PS
FROM dbo.ArretProductionJournee
where ArretProductionJournee.EnumArret Like 'HI'OR
ArretProductionJournee.EnumArret Like 'PS'
group by ArretProductionJournee.EnumArret, dbo.ArretProductionJournee.DateArret
Result :
DateArret ||HI || PS
2020-10-30 ||12 || NULL
2020-11-30 ||60 || NULL
2020-11-30 ||NULL || 60
The result i want is Grouping the sum by the date:
DateArret ||HI || PS
2020-10-30 ||12 || 0
2020-11-30 ||60 || 60
I think you want conditional aggregation:
select datearret,
sum(case when enumarret = 'PS' then datediff(minute, heuredebut, heurefin) else 0 end) ps,
sum(case when enumarret = 'HI' then datediff(minute, heuredebut, heurefin) else 0 end) hi
from dbo.arretproductionjournee
where enumarret in ('PS', 'HI')
group by datearret
I have a table with the following structure:
EOM ID Principal Pay_plan cum_Payments
2019-12-31 AY4525 25000.000000 796.000000 936.000000
2020-01-31 AY4525 25000.000000 1592.000000 936.000000
2020-02-29 AY4525 25000.000000 2388.000000 936.000000
2020-03-31 AY4525 25000.000000 3184.000000 3184.00000
2020-04-30 AY4525 25000.000000 3980.000000 3980.00000
2020-05-31 AY4525 25000.000000 4776.000000 3980.00000
2020-06-30 AY4525 25000.000000 5572.000000 3980.00000
2020-04-30 KD4525 35000.000000 500.000000 500.000000
2020-05-31 KD4525 35000.000000 1000.000000 1000.00000
2020-06-30 KD4525 35000.000000 1500.000000 1000.00000
2020-07-31 KD4525 35000.000000 2000.000000 2500.00000
So I have a cumulative payment plan and cumulative payments for unique client IDs per month. Now I want to add a column which starts counting months that the client is late with payments, hence when pay_plan > cum_payments:
EOM ID Principal Pay_plan cum_Payments months_Late
2019-12-31 AY4525 25000.000000 796.000000 936.000000 0
2020-01-31 AY4525 25000.000000 1592.000000 936.000000 1
2020-02-29 AY4525 25000.000000 2388.000000 936.000000 2
2020-03-31 AY4525 25000.000000 3184.000000 3184.00000 0
2020-04-30 AY4525 25000.000000 3980.000000 3980.00000 0
2020-05-31 AY4525 25000.000000 4776.000000 3980.00000 1
2020-06-30 AY4525 25000.000000 5572.000000 3980.00000 2
2020-04-30 KD4525 35000.000000 500.000000 500.000000 0
2020-05-31 KD4525 35000.000000 1000.000000 1000.00000 0
2020-06-30 KD4525 35000.000000 1500.000000 1000.00000 1
2020-07-31 KD4525 35000.000000 2000.000000 2500.00000 0
The counter must be reset when pay_plan = cum_payments again. I have tried numerous ways of doing this with OVER(), but not found a solid solution. Anyone got an idea how to solve this?
This is a gaps-and-islands problem. The islands are when the cumulative amount is less than the planned amount. So, you can use a cumulative sum to define the islands and then row_number():
select t.*,
(case when cum_payments >= pay_plan then 0
else row_number() over (partition by id, grp order by eom) - 1
end) as months_late
from (select t.*,
sum(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
from t
) t;
Here is a db<>fiddle.
You can handle the situation where the first payment is late by using:
select t.*,
(case when cum_payments >= pay_plan then 0
else row_number() over (partition by id, grp order by eom) - 1 +
(case when min(eom) over (partition by id) = min(eom) over (partition by id, grp) and
first_value(cum_payments) over (partition by id, grp order by eom) < first_value(pay_plan) over (partition by id, grp order by eom)
then 1 else 0
end)
end) as months_late
from (select t.*,
SUM(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
from t
) t
I actually left this logic out of the above, because it seems inelegant. There might be a better solution, but it does not readily occur to me. Here is the revised db<>fiddle.
If I understand your logic correct, Months_late value for your last row should be 0 and if it is correct, you can use this below logic to achieve your requirement-
Demo Here
Let cum_Payments will always increase or same per day for a specific ID
SELECT *,
(
SELECT COUNT(*)
FROM your_table B
WHERE B.cum_Payments = A.cum_Payments
AND B.EOM < A.EOM
AND B.ID = A.ID
) Months_late
FROM your_table A
ORDER BY ID,EOM
This following query will return the exact result as you are looking for. It is true that the query is bit heavy for a table with huge data but it is acceptable if you have one time use of this query. In case or more use, you can think about creating a view for improving query execution performance.
Demo2 Here
SELECT *,
(
SELECT count(1) FROM your_table b
WHERE b.id = a.id AND b.eom <= a.eom
AND b.eom >
(
ISNULL
(
(
SELECT MAX(eom) FROM your_table c
WHERE c.id = a.id AND (c.pay_plan - c.cum_payments) = 0
AND c.eom <= a.eom
)
,
(
SELECT MIN(eom) FROM your_table d
WHERE d.id = a.id
)
)
)
)
FROM your_table a
ORDER BY id, eom
I have the following data shown below. It was produced by the following query:
;with noms as
(
select DateS, Region, Sales from tblSalesRegion
where Id = 'B2PM'
)
select * from
noms as source pivot (max(Sales) for Region in ([UK],[US],[EUxUK],[JAP],[Brazil])) as pvt
order by DateS
Data:
DateS UK US EUxUK JAP Brazil
2015-11-24 23634 22187 NULL NULL NULL
2015-11-30 23634 22187 NULL NULL NULL
2015-12-01 23634 22187 NULL NULL NULL
2015-12-02 23634 22187 NULL NULL NULL
2015-12-03 23634 22187 NULL NULL NULL
2015-12-04 56000 22187 NULL NULL NULL
2015-12-07 56000 22187 NULL NULL NULL
2015-12-08 56000 22187 NULL NULL NULL
2015-12-09 56000 22187 NULL NULL NULL
2015-12-10 56000 10025 NULL NULL NULL
2015-12-11 56000 10025 NULL NULL NULL
2015-12-14 56000 10025 NULL NULL NULL
Below is the result I'm after. So basically when one of the values changes in one of the five columns (excluding the dateS column) I want that to be shown. Is there a way to do this in Sql? As I need the date I don't think a simple group by statement would work. Also be nice if I could change the NULL's to zeros
Result I'm looking for:
DateS UK US EUxUK JAP Brazil
2015-11-24 23634 22187 0 0 0
2015-12-04 56000 22187 0 0 0
2015-12-10 56000 10025 0 0 0
Seems like a simple GROUP BY is what you want:
;WITH noms AS
(
SELECT DateS, Region, Sales
FROM tblSalesRegion
WHERE Id = 'B2PM'
)
SELECT MIN(DateS), [UK],[US],[EUxUK],[JAP],[Brazil]
FROM (
SELECT DateS,
COALESCE([UK], 0) AS [UK],
COALESCE([US], 0) AS [US],
COALESCE([EUxUK], 0) AS [EUxUK],
COALESCE([JAP], 0) AS [JAP],
COALESCE([Brazil], 0) AS [Brazil]
FROM noms AS source
PIVOT (
MAX(Sales) FOR Region IN ([UK],[US],[EUxUK],[JAP],[Brazil])) AS pvt
) AS t
GROUP BY [UK],[US],[EUxUK],[JAP],[Brazil]
ORDER BY MIN(DateS)