Get Last Value Before zero - sql

I Have this table in SQL Server:
Cell1 Cell2 Cell3 Cell4 Cell5 Cell6 vbzero
3 65 **12** 0 0 0
12 4 5 1 6 8
10 0 0 0 0 0
1 90 0 0 0 0
I want get Last Value Before zero. for example in row one get 12 , and in row two get 8 because row tow don't containt zero and for row3 get 10 ,...
How can Do this in SQL Server .

Try something like ...
SELECT COALESCE( NULLIF(Column3, 0) , NULLIF(Column2, 0) , NULLIF(Column1, 0) )
FROM TableName
Test Data
DECLARE #TABLE TABLE
(Cell1 INT,Cell2 INT,Cell3 INT,Cell4 INT,Cell5 INT,Cell6 INT)
INSERT INTO #TABLE VALUES
(3 , 65 , 12, 0 , 0 , 0),
(12, 4 , 5 , 1 , 6 , 8),
(10, 0 , 0 , 0 , 0 , 0),
(1 , 90 , 0 , 0 , 0 , 0)
Query
SELECT COALESCE(
NULLIF(Cell6, 0) , NULLIF(Cell5, 0) , NULLIF(Cell4, 0)
,NULLIF(Cell3, 0) , NULLIF(Cell2, 0) , NULLIF(Cell1, 0)
)
FROM #TABLE
Result
12
8
10
90

Related

Adding total of a row and a col given certain conditions

I have this query :
select pivot_table.*
from (
Select STATUS,USER_TYPE
FROM TRANSACTIONS tr
join TRANSACTION_STATUS_CODES sc on sc.id = tr.user_type
join TRANSACTION_USER_TYPES ut on ut.id=tr.user_type
WHERE Tr.User_Type between 1 and 5
And tr.status!=1
AND Tr.Update_Date BETWEEN TO_DATE('2022-01-01 00:00:00', 'yyyy-mm-dd HH24:MI:SS')
AND TO_DATE('2022-11-13 23:59:59', 'yyyy-mm-dd HH24:MI:SS')
) t
pivot(
count(user_type)
FOR user_type IN (1,2,3,5)
) pivot_table;
Which gives:
status
1
2
3
5
2
3
0
0
0
4
13
0
0
0
5
1
0
0
0
3
5
0
0
1
0
4
0
0
8
Wanted result:
status
1
2
3
5
total
2
3
0
0
0
3
4
13
0
0
0
13
5
1
0
0
0
1
3
5
0
0
1
6
0
4
0
0
8
12
sum of statuses 2,4,5
17
0
0
0
17
sum of all statuses
26
0
0
0
35
I have tried adding:
Select STATUS,USER_TYPE,
count(user_type) as records,
sum(user_type) over (partition by status) as total
and in the end:
pivot ( sum (records) for user_type in (1,2,3,5)) pivot_table
but logically I am still not there.
You want to use GROUP BY CUBE with conditional aggregation and filters on the grouping sets:
SELECT CASE GROUPING_ID(status, CASE WHEN status IN (2, 4, 5) THEN 1 ELSE 0 END)
WHEN 0
THEN TO_CHAR(status)
WHEN 2
THEN 'SUB-TOTAL'
ELSE 'TOTAL'
END AS status,
COUNT(CASE user_type WHEN 1 THEN 1 END) AS "1",
COUNT(CASE user_type WHEN 2 THEN 1 END) AS "2",
COUNT(CASE user_type WHEN 3 THEN 1 END) AS "3",
COUNT(CASE user_type WHEN 5 THEN 1 END) AS "5",
COUNT(*) AS total
FROM table_name
GROUP BY CUBE(status, CASE WHEN status IN (2, 4, 5) THEN 1 ELSE 0 END)
HAVING GROUPING_ID(status, CASE WHEN status IN (2, 4, 5) THEN 1 ELSE 0 END) IN (0, 3)
OR ( GROUPING_ID(status, CASE WHEN status IN (2, 4, 5) THEN 1 ELSE 0 END) = 2
AND CASE WHEN status IN (2, 4, 5) THEN 1 ELSE 0 END = 1 )
Which, for the sample data (representing the output of your many joined tables):
CREATE TABLE table_name (status, user_type) AS
SELECT 2, 1 FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT 4, 1 FROM DUAL CONNECT BY LEVEL <= 13 UNION ALL
SELECT 5, 1 FROM DUAL CONNECT BY LEVEL <= 1 UNION ALL
SELECT 3, 1 FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT 3, 5 FROM DUAL CONNECT BY LEVEL <= 1 UNION ALL
SELECT 0, 1 FROM DUAL CONNECT BY LEVEL <= 4 UNION ALL
SELECT 0, 5 FROM DUAL CONNECT BY LEVEL <= 8;
Outputs:
STATUS
1
2
3
5
TOTAL
0
4
0
0
8
12
3
5
0
0
1
6
2
3
0
0
0
3
4
13
0
0
0
13
5
1
0
0
0
1
SUB-TOTAL
17
0
0
0
17
TOTAL
26
0
0
9
35
You can change the string literals to match the row titles for your desired output.
fiddle
One of the options to do it is to use MODEL clause like this:
Select
*
From
(
Select Cast(p.STATUS as VARCHAR2(30)) "STATUS", p."1", p."2", p."3", p."5"
From pivot_table p Union All
Select 'Sum of Statuses 2, 4, 5', Null, Null, Null, Null From Dual Union All
Select 'Sum of All Statuses', Null, Null, Null, Null From Dual
)
MODEL
Dimension By (STATUS)
Measures ("1", "2", "3", "5", 0 "TOTAL")
Rules
(
"1"['Sum of All Statuses'] = Sum("1")[ANY], -- Grand Total of Column 1 = Sum(1) for ANY Status (Dimension)
"2"['Sum of All Statuses'] = Sum("2")[ANY],
"3"['Sum of All Statuses'] = Sum("3")[ANY],
"5"['Sum of All Statuses'] = Sum("5")[ANY],
--
"1"['Sum of Statuses 2, 4, 5'] = Sum("1")[STATUS IN('2', '4', '5')], -- SubTotal of Column 1 = Sum(1) for Status IN 2, 4, 5
"2"['Sum of Statuses 2, 4, 5'] = Sum("2")[STATUS IN('2', '4', '5')],
"3"['Sum of Statuses 2, 4, 5'] = Sum("3")[STATUS IN('2', '4', '5')],
"5"['Sum of Statuses 2, 4, 5'] = Sum("5")[STATUS IN('2', '4', '5')],
--
TOTAL[ANY] = "1"[CV()] + "2"[CV()] + "3"[CV()] + "5"[CV()] -- for each row do the addition of columns with the same Current Value 'CV()' of Status
)
With the data from your question:
WITH
pivot_table AS
(
Select 2 "STATUS", 3 "1", 0 "2", 0 "3", 0 "5" From Dual Union All
Select 4 "STATUS", 13 "1", 0 "2", 0 "3", 0 "5" From Dual Union All
Select 5 "STATUS", 1 "1", 0 "2", 0 "3", 0 "5" From Dual Union All
Select 3 "STATUS", 5 "1", 0 "2", 0 "3", 1 "5" From Dual Union All
Select 0 "STATUS", 4 "1", 0 "2", 0 "3", 8 "5" From Dual
)
The result should be:
STATUS
1
2
3
5
TOTAL
2
3
0
0
0
3
4
13
0
0
0
13
5
1
0
0
0
1
3
5
0
0
1
6
0
4
0
0
8
12
Sum of Statuses 2, 4, 5
17
0
0
0
17
Sum of All Statuses
26
0
0
9
35
Regards...

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

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

How to get conditional SUM?

I am trying to get a conditional sum based on another column. For example, suppose I have this dataset:
ID Date Type Total
-----------------------
5 12/16/2019 0 7
5 12/16/2019 1 0
5 12/17/2019 0 7
5 12/17/2019 1 7
5 12/18/2019 0 7
5 12/18/2019 1 0
5 12/19/2019 0 7
5 12/19/2019 1 7
5 12/20/2019 0 7
5 12/20/2019 1 7
5 12/23/2019 0 7
5 12/24/2019 0 7
5 12/25/2019 0 7
5 12/26/2019 0 7
5 12/27/2019 0 7
If there is a type of 1 then I only want that data for that data, else if there is only 0 then I want that data for that date.
So for 12/16/2019 I would want the value 0. For 12/23/2019 - 12/27/2019 I would want the value 7.
You can use row_number() :
select t.*
from (select t.*, row_number() over (partition by id, date order by type desc) as seq
from table t
) t
where seq = 1;
A simple ROW_NUMBER can handle this quite easily. I changed some of the column names because reserved words are just painful to work with.
declare #Something table
(
ID int
, SomeDate Date
, MyType int
, Total int
)
insert #Something values
(5, '12/16/2019', 0, 7)
, (5, '12/16/2019', 1, 0)
, (5, '12/17/2019', 0, 7)
, (5, '12/17/2019', 1, 7)
, (5, '12/18/2019', 0, 7)
, (5, '12/18/2019', 1, 0)
, (5, '12/19/2019', 0, 7)
, (5, '12/19/2019', 1, 7)
, (5, '12/20/2019', 0, 7)
, (5, '12/20/2019', 1, 7)
, (5, '12/23/2019', 0, 7)
, (5, '12/24/2019', 0, 7)
, (5, '12/25/2019', 0, 7)
, (5, '12/26/2019', 0, 7)
, (5, '12/27/2019', 0, 7)
select ID
, SomeDate
, MyType
, Total
from
(
select *
, RowNum = ROW_NUMBER()over(partition by SomeDate order by MyType)
from #Something
) x
where x.RowNum = 1
You can do this with simple aggregation . . . well, and case:
select id, date, max(type),
coalesce(max(case when type = 1 then total end),
max(total)
) as total
from t
group by id, date;
This formulation is assuming that you have only types 0 and 1 and at most one of each type on each day for a given id.

Total Sum and Partial Sum

I am currently using SSMS. I am pulling data, and trying to get two different columns that sum prices. The two columns 'ChangeSpend' and 'TotalSpend' both reference the same column and this is where I am running into problems.
I want ChangeSpend to return the sum of all the codes per receipt that start with V.Ch% (so they exclude all the others) and the TotalSpend to sum all of the codes for each receipt.
Here is my current code:
SELECT
Receipt
,ReceiptCode
,ReceiptAmount
,sum(ReceiptAmount) over (Partition by Receipt) as TotalSpend
,(CASE WHEN ReceiptCode = 'V.Ch%' then sum(ReceiptAmount)
over (Partition by Receipt)
ELSE 0
END) as ChangeSpend
FROM tableA
LEFT OUTER JOIN tableB
on A.Receipt = B.Receipt
WHERE ReceiptCode LIKE 'V.%'
ORDER BY Receipt
However, my query currently prints this:
Receipt ReceiptCode ReceiptAmount TotalSpend ChangeSpend
1 v.cha 5 20 0
1 v.rt 2 20 0
1 v.chb 6 20 0
1 v.abc 7 20 0
2 v.cha 20 21 0
2 v.abc 1 21 0
3 v.cha 4 14 0
3 v.chb 1 14 0
3 v.tye 7 14 0
3 v.chs 2 14 0
And I would like it to print this:
Receipt ReceiptCode ReceiptAmount TotalSpend ChangeSpend
1 v.cha 5 20 11
1 v.rt 2 20 11
1 v.chb 6 20 11
1 v.abc 7 20 11
2 v.cha 20 21 20
2 v.abc 1 21 20
3 v.cha 4 14 7
3 v.chb 1 14 7
3 v.tye 7 14 7
3 v.chs 2 14 7
Thanks for any help
Try
,SUM(CASE WHEN ReceiptCode LIKE 'V.Ch%' THEN ReceiptAmount ELSE 0 END)
OVER (Partition by Receipt)
AS ChangeSpend
You have to put the SUM outside the CASE, not the other way around:
SUM(CASE WHEN SomeCondition=true THEN MyColumn ELSE 0 END)
This may help:
Create Table Payment(
Receipt Int,
ReceiptCode VARCHAR(10),
ReceiptAmount decimal)
Insert Into Payment
Values
(1, 'v.cha', 5),
(1, 'v.rt', 2),
(1, 'v.chb', 6),
(1, 'v.abc', 7),
(2, 'v.cha', 20),
(2, 'v.abc', 1),
(3, 'v.cha', 4),
(3, 'v.chb', 1),
(3, 'v.the', 7),
(3, 'v.chs', 2);
SELECT * ,
SUM(ReceiptAmount) OVER ( PARTITION BY Receipt ) AS TotalSpend ,
SUM(IIF(ReceiptCode LIKE 'v.ch%',ReceiptAmount,0)) OVER ( PARTITION
BY Receipt ) AS ChangeSpend
FROM payment;
Result:
SUM(
CASE WHEN ReceiptCode like 'V.Ch%' then ReceiptAmount ELSE 0 END) as ChangeSpend

SQL Server : data between specific range

I have a data which is something like this
stories value
--------------------------
0 2194940472.78964
1 1651820586.1447
2 627935051.75
3 586994698.4272
4 89132137.57
5 134608008
6 40759564
7 0
8 0
10 0
11 0
12 0
13 26060602
17 0
18 0
19 84522335
20 316478066.045
24 0
I want to sum it up as per the range
Output which I am expected
stories value
0-3 125201021
4-7 215453123
8-12 453121545
12-max(numstories) 21354322
I tried this but not able to figure it out what is wrong
select t.NumStories, SUM(t.bldnvalue)
from
(select
a.NumStories,
case
when a.NumStories between 0 and 3 then sum(a.BldgValue)
when a.NumStories between 4 and 7 then sum(a.BldgValue)
when a.NumStories between 8 and 12 then sum(a.BldgValue)
when a.NumStories between 13 and max(a.NumStories) then sum(a.BldgValue)
end as bldnvalue
from
dbo.EDM_CocaCola_Coca_Cola_Company_1_1 a
group by
a.NumStories) t
group by
t.NumStories
With this query I am getting this output
NumStories value
-------------------------------
0 2194940472.78964
3 586994698.4272
12 0
6 40759564
7 0
1 1651820586.1447
24 0
18 0
10 0
4 89132137.57
19 84522335
13 26060602
5 134608008
2 627935051.75
17 0
11 0
20 316478066.045
8 0
I like this result, I tried to use the BIN concept. I think the only issue would be with your max bin. I don't understand how you got your output sums. the first records value is '2,194,940,472.78964' which is bigger than your value in 0-3 bin
if OBJECT_ID('tempdb..#Test') is not null
drop table #Test;
Create table #Test (
Stories int
, Value float
)
insert into #Test
values
(0 , 2194940472.78964)
, (1 , 1651820586.1447 )
, (2 , 627935051.75 )
, (3 , 586994698.4272 )
, (4 , 89132137.57 )
, (5 , 134608008 )
, (6 , 40759564 )
, (7 , 0 )
, (8 , 0 )
, (10, 0 )
, (11, 0 )
, (12, 0 )
, (13, 26060602 )
, (17, 0 )
, (18, 0 )
, (19, 84522335 )
, (20, 316478066.045 )
, (24, 0 )
if OBJECT_ID('tempdb..#Bins') is not null
drop table #Bins;
create Table #Bins(
Label varchar(20)
, Min int
, Max int
)
insert into #Bins values
('0-3', 0, 3)
, ('4-7', 4, 7)
, ('8-12', 8, 12)
, ('13 - Max', 13, 999999999)
Select b.Label
, sum(t.Value) as Value
from #Test t
join #Bins b
on t.stories between b.Min and b.Max
Group by b.Label
order by 1
Output:
Label Value
-------------------- ----------------------
0-3 5061690809.11154
13 - Max 427061003.045
4-7 264499709.57
8-12 0
Just build the grouping string first that you want and group by that variable.
select
case
when a.NumStories between 0 and 3 then '0-3'
when a.NumStories between 4 and 7 then '4-7'
when a.NumStories between 8 and 12 then '8-12'
when a.NumStories >= 13 then '13-max'
end as stories,
sum(a.BldgValue) as value
from
dbo.EDM_CocaCola_Coca_Cola_Company_1_1 a
group by 1;
If you really want to print the max too, then you can put in a subquery in the "13-max" line as (SELECT MAX(BldgValue) FROM dbo.EDM_CocaCola_Coca_Cola_Company_1_1)
You can try this:
SELECT '0-3' AS stories,
SUM(value) AS value
FROM dbo.EDM_CocaCola_Coca_Cola_Company_1_1
WHERE stories BETWEEN 0 AND 3
UNION ALL
SELECT '4-7' AS stories,
SUM(value) AS value
FROM dbo.EDM_CocaCola_Coca_Cola_Company_1_1
WHERE stories BETWEEN 4 AND 7
UNION ALL
...
Here is solution with CTE that should work for any data set, without copying the code.
declare #YourTable table(stories int, value money)
declare #GroupMemberCount int=4
insert #YourTable (stories,value) values (0,5),(1,10),(2,11),(3,7),(4,18),(5,13),(7,15)
;with cte as
(
select c.stories+v.i*#GroupMemberCount FirstGroupMember, c.stories+v.i*#GroupMemberCount+#GroupMemberCount -1 LastGroupMember
,CAST(c.stories+v.i*#GroupMemberCount as varchar(50))
+'-'+CAST(c.stories+v.i*#GroupMemberCount+#GroupMemberCount -1 as varchar(50))GroupName
from (select MIN(stories) stories from #YourTable) c
cross join (values (0),(1),(2),(3),(4)/* and so on */) v(i)
where exists (select * from #YourTable yt where yt.stories>=c.stories+v.i*3)
)
select c.GroupName, SUM(yt.value)
from cte c
JOIN #YourTable yt ON yt.stories BETWEEN c.FirstGroupMember AND C.LastGroupMember
GROUP BY c.GroupName