U-SQL - SUM of a CASE Statement - c#

I have a table with customer transactions that I'm trying to aggregate by customer and department.
Cust_id trans_num sku dept qty price
123 234 345 1 2 15.99
123 345 887 1 1 12.99
123 678 445 2 1 21.89
234 345 998 1 1 7.99
In SQL I'd do something like this:
SELECT Cust_id
, SUM(CASE WHEN dept = 1 THEN (price * qty) ELSE 0 END ) dept_1_spend
, SUM(CASE WHEN dept = 2 THEN (price * qty) ELSE 0 END ) dept_2_spend
from tab1
group by Cust_id
The U-SQL docs here mention ? as the C# equivalent but I'm not sure how to SUM the values.
What's the equivalent in U-SQL?

You can try ternary operator in C#:
SELECT Cust_id
, SUM(dept == 1 ? price * qty : 0) AS dept_1_spend
, SUM(dept == 2 ? price * qty : 0) AS dept_2_spend
from tab1
group by Cust_id

You can also you the U-SQL PIVOT operator, eg
#tab1 =
SELECT *
FROM(
VALUES
(123,234,345,1,2,15.99),
(123,345,887,1,1,12.99),
(123,678,445,2,1,21.89),
(234,345,998,1,1,7.99)) AS T(Cust_id,trans_num,sku,dept,qty,price);
#res =
SELECT Cust_id,
SUM([1]) AS dept_1_spend,
SUM([2]) AS dept_2_spend
FROM
(
SELECT Cust_id, dept, price * qty AS spend
FROM #tab1
) AS t
PIVOT (SUM(spend) FOR dept IN ( 1 AS [1], 2 AS [2] )
) AS pvt
GROUP BY Cust_id;
OUTPUT #res
TO "/output/sum_case.csv"
USING Outputters.Csv();
More information on U-SQL PIVOT available here.

You can even use the SQL's CASE expression. You will need the C# == and use AS to designate the column aliases and use upper-case for the keywords. But otherwise looks like your query:
#tab1 =
SELECT *
FROM(
VALUES
(123,234,345,1,2,15.99),
(123,345,887,1,1,12.99),
(123,678,445,2,1,21.89),
(234,345,998,1,1,7.99)) AS T(Cust_id,trans_num,sku,dept,qty,price);
#res =
SELECT Cust_id,
SUM(CASE WHEN dept == 1 THEN(price * qty) ELSE 0 END) AS dept_1_spend,
SUM(CASE WHEN dept == 2 THEN(price * qty) ELSE 0 END) AS dept_2_spend
FROM #tab1
GROUP BY Cust_id;
OUTPUT #res
TO "/output/sum_case.csv"
USING Outputters.Csv();
I personally prefer the C# ternary if.

Related

Combine multi row to single row and fill in the missing value by using sql, Function or ... in DB2

I need your help i Have Raw Data Below.
Student Name Period Class
_____________________________
Samnang 2019-03-31 0
Samnang 2019-05-31 1
Samnang 2019-08-31 2
Samnang 2019-09-30 3
Samnang 2019-10-31 4
And I want result below using Sql, Function or ... in DB2:
Note: Missing Month will be replaced by "M" (Mission Month)
Student Name Class
__________________________
Samnang 0M1MM234
WITH
Student (Name, Period, Class) AS
(
VALUES
('Samnang', DATE('2019-03-31'), 0)
, ('Samnang', DATE('2019-05-31'), 1)
, ('Samnang', DATE('2019-08-31'), 2)
, ('Samnang', DATE('2019-09-30'), 3)
, ('Samnang', DATE('2019-10-31'), 4)
, ('Samnang1', DATE('2019-01-31'), 0)
, ('Samnang1', DATE('2019-03-31'), 1)
, ('Samnang1', DATE('2019-07-31'), 2)
)
,
DATE_RANGE AS
(
SELECT
Name
, MIN(PERIOD) - (DAY(MIN(PERIOD)) - 1) DAYS PERIOD_MIN
, MAX(PERIOD) - (DAY(MAX(PERIOD)) - 1) DAYS PERIOD_MAX
FROM student
GROUP BY Name
)
, T (NAME, PERIOD, PERIOD_MAX, PERIOD_YEAR, PERIOD_MONTH) AS
(
SELECT NAME, PERIOD_MIN, PERIOD_MAX, YEAR(PERIOD_MIN), MONTH(PERIOD_MIN)
FROM DATE_RANGE
UNION ALL
SELECT NAME, PERIOD + 1 MONTH, PERIOD_MAX, YEAR(PERIOD + 1 MONTH), MONTH(PERIOD + 1 MONTH)
FROM T
WHERE PERIOD < PERIOD_MAX
)
SELECT T.NAME, LISTAGG(COALESCE(TRIM(CHAR(S.CLASS)), 'M')) WITHIN GROUP (ORDER BY T.PERIOD_YEAR, T.PERIOD_MONTH) CLASS
FROM T
LEFT JOIN STUDENT S ON S.NAME = T.NAME AND YEAR(S.PERIOD) = T.PERIOD_YEAR AND MONTH(S.PERIOD) = T.PERIOD_MONTH
GROUP BY T.NAME;
|NAME |CLASS |
|--------|--------|
|Samnang |0M1MM234|
|Samnang1|0M1MMM2 |

Update each row value until it goes 0

I'm an creating an inventory program for a company .I have a table with data on SQL Server
|product|stock |
|A |15 |
|B |26 |
|C |27 |
|D |18 |
I want to subtract a quantity x=70 on each product on the table until the product goes 0. For example: subtract x on the product A until it goes 0 (70-15=55). Then this difference subtracts the Product B until it goes 0 (55-26=29). And so on the Product C (29-27=2). Then on Product D (18-2=16).
In the end the table would be:
|product|stock |
|A |0 |
|B |0 |
|C |0 |
|D |16 |
I need a way to do this is SQL database.Thanks
You could use SUM()...OVER()
DECLARE #SampleTable AS TABLE
(
Product varchar(10),
Stock int
)
INSERT INTO #SampleTable
VALUES ('A', 15),('B', 26),('C', 27),('D', 18), ('E', 20)
DECLARE #TotalStock int = 70
SELECT st.Product ,
CASE
WHEN sum(st.Stock) OVER(ORDER BY (st.Product)) < #TotalStock THEN 0
WHEN sum(st.Stock) OVER(ORDER BY (st.Product)) - #TotalStock < st.Stock THEN sum(st.Stock) OVER(ORDER BY (st.Product)) - #TotalStock
ELSE st.Stock
END AS stock
FROM #SampleTable st
Another approach you could use CROSS APPLY
;WITH temp AS
(
SELECT *, Row_number() OVER(ORDER BY(SELECT 1)) AS RowIndex
FROM #SampleTable st
)
SELECT st.Product,
CASE
WHEN ca.realstock < 0 THEN 0
WHEN ca.realstock < st.Stock THEN ca.realstock
ELSE st.Stock
END AS stock
FROM temp st
CROSS APPLY
(
SELECT isnull(sum(st2.Stock),0) - #TotalStock AS realstock
FROM temp st2
WHERE st2.RowIndex <= st.RowIndex
) ca
See demo for 2 approaches: Rextester
You can use window function sum to find cumulative sum of stock in the order of product (check if you need ordering on some other basis) and use that a filter rows:
select *
from (
select t.*,
sum(stock) over (
order by product
) as cumulative_sum
from your_table t
) t
where cumulative_sum - stock <= 70;

Fetch alternate series of records in SQL Server

I want to get alternate series of records using SQL Server.
For example :
I want to skip first 10 records (1 to 10) in sequence and get other 10 records (11 to 20) after that I want to skip next 10 records (21 to 30) and get another next 10 records (31 to 40)
I have done for alternate rows as below...
SELECT ROW, EmployeeID
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY EmployeeID) AS ROW, *
FROM Employee) A
WHERE
ROW % 2 = 0
But in case of my requirement above logic will not work. Please help me to make above thing works..
Linq will also accepted
Thanks
SELECT ROW, EmployeeID
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY EmployeeID) AS ROW, *
FROM Employee) A
WHERE
((ROW - 1)/10) % 2 = 1
I have done above of your requirement like below (Example).
Generated 1200 number sequentially from 1 to 1200 like below
;WITH CTE
AS
(
SELECT 1 PERIOD_SID
UNION ALL
SELECT PERIOD_SID+1 FROM CTE WHERE PERIOD_SID<1200
)
SELECT * INTO #PERIOD1 FROM CTE
OPTION(MAXRECURSION 0)
After this i have find alternative numbers like you have mentioned in your query
SELECT PERIOD_SID FROM
(
SELECT CASE
WHEN PERIOD_SID%10 <> 0 THEN PERIOD_SID / 10
WHEN PERIOD_SID%10 = 0 THEN ( PERIOD_SID / 10 ) - 1
END RNO,
PERIOD_SID
FROM #PERIOD1 )A
WHERE RNO%2=0
so if you have sequential numbers in your query (If you dont have generate using rownumber) then apply above logic.
Your query need to convert like below.
SELECT EMPLOYEEID
FROM (SELECT Row_number()
OVER (
ORDER BY EMPLOYEEID)AS ROW,
*
FROM EMPLOYEE) A
WHERE ( CASE
WHEN RNO%10 <> 0 THEN RNO / 10
WHEN RNO%10 = 0 THEN ( RNO / 10 ) - 1
END )%2 = 0
may be you can try this
SELECT ROW, EmployeeID FROM(
SELECT ROW_NUMBER()OVER (ORDER BY EmployeeID)AS ROW,* FROM Employee)
A WHERE ((ROW - (ROW%10))/10) % 2 = 1
Don't if this works or not coz I dont have sql server to run. Please show the error/result after running this query.
Ask if any doubt.

How to use Pivot table for calculating in this scenario?

How to get the below result from the given data.
Report
-------------------------------------------------
ID | Name | Status
-------------------------------------------------
1 | A | Inprogress
2 | A | Inprogress
3 | A | Complete
I need to calculate the result like
---------------------------------------------
Name | Total | Complete | Remaining
---------------------------------------------
A | 3 | 1 | 2
SQL:
Select
[Inprogress], [Complete], [Printed]
from
(select
specimenID, count([RStatus])
from tbl_LabReport
group by specimenID) as sourcetable
Pivot
(Count(specimenID) for [RStatus] in ( [Inprogress],[Complete],[Printed] )) as ptv
You don't need to use PIVOT operator. Try to use subquery or CROSS APPLY operator to solve your task
;WITH test_data AS(
SELECT 1 AS id, 'A' AS NAME, 'Inprogress' AS [status]
UNION ALL
SELECT 2, 'A', 'Inprogress'
UNION ALL
SELECT 3, 'A', 'Complete'
UNION ALL
SELECT 4, 'B', 'Complete'
)
SELECT DISTINCT
name,
T3.*
FROM test_data AS T
CROSS APPLY (SELECT COUNT(*) AS total,
SUM(CASE WHEN T2.status = 'Complete' THEN 1 ELSE 0 END) AS complete,
SUM(CASE WHEN T2.status = 'Inprogress' THEN 1 ELSE 0 END) AS remaining
FROM test_data AS T2
WHERE T2.name = T.name) AS T3
There are a few approaches you could take. This example uses CASE expressions. If you are not familiar with the concept a CASE allows you to conditional return a selected value. I've converted your sample data into table variable:
Sample Data
/* Creating sample data inside a table variable makes it
* easy to share.
*/
DECLARE #Sample TABLE
(
ID INT,
Name VARCHAR(50),
[Status] VARCHAR(50)
)
;
/* Sample values taken from OP.
*/
INSERT INTO #Sample
(
ID,
Name,
[Status]
)
VALUES
(1, 'A', 'Inprogress'),
(2, 'A', 'Inprogress'),
(3, 'A', 'Complete')
;
The CASE returns a 1 for the required Status and a 0 for everything else. Summing the result provides sub totals.
/* Using CASE to return conditional sub totals.
*/
SELECT
Name,
COUNT([Status]) AS Total,
SUM(CASE WHEN [Status] = 'Complete' THEN 1 ELSE 0 END) AS Complete,
SUM(CASE WHEN [Status] = 'Inprogress' THEN 1 ELSE 0 END) AS Remaining
FROM
#Sample
GROUP BY
Name
;

Sum of row and column in SQL pivot table

price c_melli cost_teacher
150000 5099572650 1
170000 5099572650 1
170000 5099572650 1
150000 0015601218 1
170000 0015601218 1
200000 0015601218 1
200000 0015601218 2
200000 0015601218 2
200000 0015601218 1
select * from
(select * from temp) as s
PIVOT
(
SUM(price)
FOR [cost_teacher] IN ([1],[2],[3])
) as p1
result is:
c_melli 1 2 3
0015601218 720000 400000 NULL
5099572650 490000 NULL NULL
I want to add column with count of 1 and 2 and 3
and add column with sum of each row
and add a row to end for calculate each columns.
Please help me.
Select t.c_melli, s.[1], c.[1], s.[2], c.[2], s[3], c.[3], s.[1]+s.[2]+s.[3] as sumRow from (select distinct c_Melli from temp) t
inner join(
select * from
(select * from temp) as s
PIVOT
(
SUM(price)
FOR [cost_teacher] IN ([1],[2],[3])
) as p1
) s on s.mellicode = t.mellicode
inner join(
select * from
(select * from temp) as s
PIVOT
(
Count(price)
FOR [cost_teacher] IN ([1],[2],[3])
) as p1
) c on c.mellicode = t.mellicode
I usually advise that people do their summary lines in the reporting tool or web page or wherever the data is going. It's too easy to get the total line mixed in with the detail lines if the record order isn't rigidly defined.
But what you want is possible, and here's a way to do it:
;
-- Turning the original query into a CTE allows us to easily re-use it in the query
with detail as (
select c_melli
, [1]
, [2]
, [3]
from
(select * from temp) as s
PIVOT
(
SUM(price)
FOR [cost_teacher] IN ([1],[2],[3])
) as p1
)
-- The first SELECT retrieves the detail pivoted row, plus a calculated total of all columns.
select c_melli
, [1]
, [2]
, [3]
, row_total = COALESCE([1],0) + COALESCE([2],0) + COALESCE([3],0)
from detail
-- using "union all" rather than "union" because "union all" skips the
-- duplicate-removal step (which we don't need) and is therefore faster.
union all
-- The section SELECT summarizes all of the detail rows.
select 'total' -- this assumes c_melli is a string; if not, use something else
, SUM([1])
, SUM([2])
, SUM([3])
, SUM(COALESCE([1],0) + COALESCE([2],0) + COALESCE([3],0))
from detail
Disclaimer: I did this from memory and have not tested it.
How about using WITH ROLLUP?
SELECT CASE WHEN (GROUPING(c_melli) = 1) THEN 'Total'
ELSE ISNULL(c_melli, 'UNKNOWN')
END as c_melli,
[1], [2], [3], [1]+[2]+[3] as Total
FROM
(select * from temp) as s
PIVOT
(
SUM(price)
FOR [cost_teacher] IN ([1],[2],[3])
) as p1
GROUP BY c_melli WITH ROLLUP

Categories