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;
Related
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.
I have this table:
ID
00001
00001
00002
00002
00003
00004
00004
00004
00005
If the SqlDataReader reaches the 5th column (which is the 00003), is there a possibility that I can compare whether the next one has the same ID as the current value before finishing the current while loop?
I will be using this to determine whether the reader will move to the next different ID, so that I can draw the controls for the last part, then move on for the next ID.
I would love to post the code but since I'm creating elements dynamically, it is very long.
EDIT:
Here is the code (cleaned to make it simple as possible):
bool isFinished = false;
string lastID = "";
while (reader.Read())
{
string transID = Convert.ToInt32(reader["ID"]).ToString("D5");
lastID = (lastID == "") ? transID : lastID;
isFinished = (lastID != transID) ? true : false;
if (isFinished)
{
LastPart();
}
initialParts();
lastID = transID;
}
With this codes, I managed to put the LastPart() after all the data with similar ID has been created. But this results in the LastPart() not being called after the last initialParts()
Here ist a Sample in SQL. In the union ALL section you can pu your query:
SELECT *
FROM
(SELECT #my_id:=#my_last_id AS new_id , #my_last_id:=id AS next_id
FROM
( SELECT *
FROM
( SELECT *
FROM
( SELECT "00001" AS id
UNION ALL SELECT "00001"
UNION ALL SELECT "00002"
UNION ALL SELECT "00002"
UNION ALL SELECT "00003"
UNION ALL SELECT "00004"
UNION ALL SELECT "00004"
UNION ALL SELECT "00004"
UNION ALL SELECT "00005" ) AS yourTable
UNION ALL SELECT NULL AS id ) tablePlusOneRow) newTable
CROSS JOIN
(SELECT #my_id:=NULL, #my_next_id:=NULL) init) AS new_table2
WHERE new_id IS NOT NULL;
sample
MariaDB [sample]> SELECT *
-> FROM
-> (SELECT #my_id:=#my_last_id AS new_id , #my_last_id:=id AS next_id
-> FROM
-> ( SELECT *
-> FROM
-> ( SELECT *
-> FROM
-> ( SELECT "00001" AS id
-> UNION ALL SELECT "00001"
-> UNION ALL SELECT "00002"
-> UNION ALL SELECT "00002"
-> UNION ALL SELECT "00003"
-> UNION ALL SELECT "00004"
-> UNION ALL SELECT "00004"
-> UNION ALL SELECT "00004"
-> UNION ALL SELECT "00005" ) AS yourTable
-> UNION ALL SELECT NULL AS id ) tablePlusOneRow) newTable
-> CROSS JOIN
-> (SELECT #my_id:=NULL, #my_next_id:=NULL) init) AS new_table2
-> WHERE new_id IS NOT NULL;
+--------+---------+
| new_id | next_id |
+--------+---------+
| 00001 | 00001 |
| 00001 | 00002 |
| 00002 | 00002 |
| 00002 | 00003 |
| 00003 | 00004 |
| 00004 | 00004 |
| 00004 | 00004 |
| 00004 | 00005 |
| 00005 | NULL |
+--------+---------+
9 rows in set (0.00 sec)
MariaDB [sample]>
speed with 1000000 ROWS
The time includes also tho time for the output 0.28 / 0.79 sec
MariaDB [sample]> select * from myids;
.....
| 999998 |
| 999999 |
| 1000000 |
+---------+
1000000 rows in set (0.28 sec)
MariaDB [sample]>
SELECT * FROM (
SELECT #my_id:=#my_last_id AS new_id , #my_last_id:=id AS next_id
FROM (
SELECT *
FROM (
SELECT *
FROM (
SELECT * FROM myids
) AS yourTable
UNION ALL
SELECT NULL AS id
) tablePlusOneRow
) newTable
CROSS JOIN ( SELECT #my_id:=NULL, #my_next_id:=NULL) init
) AS new_table2
WHERE new_id IS NOT NULL;
....
| 999998 | 999999 |
| 999999 | 1000000 |
| 1000000 | NULL |
+---------+---------+
1000000 rows in set (0.79 sec)
I want to select multiple row on a table. But I want to select fields every row too. Here is sample table :
---------------------
OrNo | Name | value
---------------------
1154 | Michael | 41
1154 | Rico | 24
1487 | Alex | 21
1487 | Leo | 27
I want to select based where "Orno" code which in the table is multiple. so I want to get every name and value on 1 of "OrNO".
For an example, I want to select where OrNO 1154. How to select all of name and value from that code? How to used sql data reader for read them?
Edit:
Based answered, I'm sorry, I want to execute on behind code, like sqldatareader with C#/VB.Net. I dont know how to execute them on behind code to store to varriable.
Thank you
SELECT *
FROM MyTable
WHERE OrNo IN
(
SELECT OrNo
FROM
(
SELECT OrNo, COUNT(*) AS RecordCount
FROM MyTable
GROUP BY OrNo
) A
WHERE RecordCount > 1
)
You want to return duplicate records per OrNo, so count per OrNo and only return records with a count > 1.
select orno, name, value
from
(
select orno, name, value, count(*) over (partition by orno) as cnt
from mytable
)
where cnt > 1
order by orno;
It's hard to understand your question.
Are you searching for the SQL Statement? If so, I would suggest:
SELECT *
FROM <TABLE_NAME>
WHERE OrNo IN
(
SELECT OrNo
FROM <TABLE_NAME>
GROUP BY OrNo
HAVING COUNT(*) > 1
)
Sorry, #jmcilhinney was faster here.
And one more, with ties
with t as (
select * from (values
(1154,'Michael',41),
(1154,'Rico',24),
(1199,'Mary',25),
(1487,'Alex',21),
(1487,'Leo',27)) t(OrNo, Name, value )
)
select top(1) with ties OrNo, Name, value
from t
order by
case count(*) over (partition by OrNo ) when 1 then 1 else 0 end
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
;
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