Sno Water Milk
1 50 100
2 22 120
3 11 142
i have this table.Now i want result like
Sno Type Qnty
1 Water 83
2 Milk 362
How can I please tell me.
SQL Server 2008 does not support this kind of statement.
You can achieve that in 2 ways:
using temporary table (variable type table)
DECLARE #products TABLE(Sno INT, Water INT, Milk INT)
INSERT INTO #products
VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)
SELECT ROW_NUMBER() OVER(ORDER BY SUM(Qnty)) AS RowNo, Product, SUM(Qnty) AS Qnty
FROM (
SELECT Product, Qnty
FROM (
SELECT *
FROM #products
) AS pvt
UNPIVOT (Qnty FOR Product IN ([Water],[Milk])) AS unpvt
) AS T
GROUP BY Product</pre>
or
;WITH T AS
(
SELECT Sno, Water, Milk
FROM (
SELECT 1 AS Sno, 50 AS Water, 100 AS Milk
UNION ALL
SELECT 2, 22, 120
UNION ALL
SELECT 3, 11, 142
) t (Sno, Water, Milk))
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) upvt
GROUP BY upvt.Type
ORDER BY Qnty;</pre>
Please,refer MSDN documentation.
The first step is to UNPIVOT your data:
WITH T AS
( SELECT Sno, Water, Milk
FROM (VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)) t (Sno, Water, Milk)
)
SELECT upvt.Sno,
upvt.Type,
Upvt.Qnty
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt;
Which will give:
Sno Type Qnty
1 Water 50
1 Milk 100
2 Water 22
2 Milk 120
3 Water 11
3 Milk 142
You can then apply normal aggregation to this result:
WITH T AS
( SELECT Sno, Water, Milk
FROM (VALUES (1, 50, 100), (2, 22, 120), (3, 11, 142)) t (Sno, Water, Milk)
)
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt
GROUP BY upvt.Type
ORDER BY Qnty;
Giving:
Sno Type Qnty
1 Water 83
2 Milk 362
EDIT
Based on your comment that you are using SQL Server 2005, not 2008 as indicated below is a full working example that will work on 2005:
DECLARE #T TABLE (Sno INT, Water INT, Milk INT);
INSERT #T (Sno, Water, Milk) VALUES (1, 50, 100);
INSERT #T (Sno, Water, Milk) VALUES(2, 22, 120);
INSERT #T (Sno, Water, Milk) VALUES(3, 11, 142);
SELECT Sno = ROW_NUMBER() OVER(ORDER BY SUM(Upvt.Qnty)),
upvt.Type,
Qnty = SUM(Upvt.Qnty)
FROM #T AS T
UNPIVOT
( Qnty
FOR Type IN ([Water], [Milk])
) AS upvt
GROUP BY upvt.Type
ORDER BY Qnty;
It was the table valued constructor I was using to create the sample data that was causing the error in 2005, nothing to do with the actual query that unpivots then sums the data.
This gives the result you asked for but I get the idea you want something a little more advanced. If so please elaborate.
SELECT 'water', sum(water) FROM table_name
UNION ALL
SELECT 'milk', sum(milk) FROM table_name
Related
the title might be a bit off however i'm trying to remove the values of a row without removing the actual row.
This is my table:
SELECT ID,CustomerID,Weight FROM Orders
What am i trying to accomplish is this:
The MAX() value of ID Group By CustomerID that would give me null values in Weight where max and group by is not set
Is it possible to do this in one line? with a partiton by?
Something like:
SELECT MAX(ID) over (partition by CustomerID,Weight).... I know this is wrong but if possible to do without a join or CTE and only in one line in the select statement that would be great.
One possible approach is using ROW_NUMBER:
SELECT
ID,
CustomerID,
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY ID DESC) = 1 THEN [Weight]
ELSE Null
END AS [Weight]
FROM #Orders
ORDER BY ID
Input:
CREATE TABLE #Orders (
ID int,
CustomerID int,
[Weight] int
)
INSERT INTO #Orders
(ID, CustomerID, [Weight])
VALUES
(1, 11, 100),
(2, 11, 17),
(3, 11, 35),
(4, 22, 26),
(5, 22, 78),
(6, 22, 10030)
Output:
ID CustomerID Weight
1 11 NULL
2 11 NULL
3 11 35
4 22 NULL
5 22 NULL
6 22 10030
Try this
;WITH CTE
AS
(
SELECT
MAX_ID = MAX(ID) OVER(PARTITION BY CustomerId),
ID,
CustomerId,
Weight
FROM Orders
)
SELECT
ID,
CustomerId,
Weight = CASE WHEN ID = MAX_ID THEN Weight ELSE NULL END
FROM CTE
You can try this.
SELECT ID,CustomerId,CASE WHEN ID= MAX(ID) OVER(PARTITION BY CustomerId) THEN Weight ELSE NULL END AS Weight FROM Orders
I have a table with sample data below.
PatId NetType
100 In
100 Out
100 NA
101 Out
101 NA
102 NA
103 In
When there are multiple netTypeid for same patient return only top one prioritized by( In,Out,NA) as order. What i am trying to do when there are In/Out/NA available for a patid then should return back only In, when there is Out/NA available for a patid then it should return back only In.If no duplicate just return back as is. Output for above scenario should be
PatId NetType
100 In
101 Out
102 NA
103 In
Use row_number() to order your table by NetType
select
PatId, NetType
from (
select
PatId, NetType
, row_number() over (partition by PatId order by case NetType when 'In' then 1 when 'Out' then 2 else 3 end) rn
from
myTable
) t
where
rn = 1
Similar to uzi
DECLARE #T AS TABLE (PatId int, NetType varchar(20));
insert into #t values
(100, 'In')
, (100, 'Out')
, (100, 'NA')
, (101, 'Out')
, (101, 'NA')
, (102, 'NA')
, (103, 'In');
DECLARE #O AS TABLE (ord int primary key, NetType varchar(20));
insert into #O values (1, 'In'), (2, 'Out'), (3, 'NA');
select tt.PatId, tt.NetType
from ( select t.*
, ROW_NUMBER() over (partition by PatId order by o.ord) as rn
from #t t
join #O o
on t.NetType = o.NetType
) tt
where tt.rn = 1;
I have a table containing orders. I would like to select those orders that are a certain number of days apart for a specific client. For example, in the table below I would like to select all of the orders for CustomerID = 10 that are at least 30 days apart from the previous instance. With the starting point to be the first occurrence (07/05/2014 in this data).
OrderID | CustomerID | OrderDate
==========================================
1 10 07/05/2014
2 10 07/15/2014
3 11 07/20/2014
4 11 08/20/2014
5 11 09/21/2014
6 10 09/23/2014
7 10 10/15/2014
8 10 10/30/2014
I would want to select OrderIDs (1,6,8) since they are 30 days apart from each other and all from CustomerID = 10. OrderIDs 2 and 7 would not be included as they are within 30 days of the previous order for that customer.
What confuses me is how to set the "checkpoint" to the last valid date. Here is a little "pseudo" SQL.
SELECT OrderID
FROM Orders
WHERE CusomerID = 10
AND OrderDate > LastValidOrderDate + 30
i came here and i saw #SveinFidjestøl already posted answer but i can't control my self after by long tried :
with the help of LAG and LEAD we can comparison between same column
and as per your Q you are looking 1,6,8. might be this is helpful
SQL SERVER 2012 and after
declare #temp table
(orderid int,
customerid int,
orderDate date
);
insert into #temp values (1, 10, '07/05/2014')
insert into #temp values (2, 10, '07/15/2014')
insert into #temp values (3, 11, '07/20/2014')
insert into #temp values (4, 11, '08/20/2014')
insert into #temp values (5, 11, '09/21/2014')
insert into #temp values (6, 10, '09/23/2014')
insert into #temp values (7, 10, '10/15/2014')
insert into #temp values (8, 10, '10/30/2014');
with cte as
(SELECT orderid,customerid,orderDate,
LAG(orderDate) OVER (ORDER BY orderid ) PreviousValue,
LEAD(orderDate) OVER (ORDER BY orderid) NextValue,
rownum = ROW_NUMBER() OVER (ORDER BY orderid)
FROM #temp
WHERE customerid = 10)
select orderid,customerid,orderDate from cte
where DATEDIFF ( day , PreviousValue , orderDate) > 30
or PreviousValue is null or NextValue is null
SQL SERVER 2005 and after
WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY p.orderid),
p.orderid,
p.customerid,
p.orderDate
FROM #temp p
where p.customerid = 10)
SELECT CTE.orderid,CTE.customerid,CTE.orderDate,
prev.orderDate PreviousValue,
nex.orderDate NextValue
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1
where CTE.customerid = 10
and
DATEDIFF ( day , prev.orderDate , CTE.orderDate) > 30
or prev.orderDate is null or nex.orderDate is null
GO
You can use the LAG() function, available in SQL Server 2012, together with a Common Table Expression. You calculate the days between the customer's current order and the customer's previous order and then query the Common Table Expression using the filter >= 30
with cte as
(select OrderId
,CustomerId
,datediff(d
,lag(orderdate) over (partition by CustomerId order by OrderDate)
,OrderDate) DaysSinceLastOrder
from Orders)
select OrderId, CustomerId, DaysSinceLastOrder
from cte
where DaysSinceLastOrder >= 30 or DaysSinceLastOrder is null
Results:
OrderId CustomerId DaysSinceLastOrder
1 10 NULL
6 10 70
3 11 NULL
4 11 31
5 11 32
(Note that 1970-01-01 is chosen arbitrarily, you may choose any date)
Update
A slighty more reliable way of doing it will involve a temporary table. But the original table tbl can be left unchanged. See here:
CREATE TABLE #tmp (id int); -- set-up temp table
INSERT INTO #tmp VALUES (1); -- plant "seed": first oid
WHILE (##ROWCOUNT>0)
INSERT INTO #tmp (id)
SELECT TOP 1 OrderId FROM tbl
WHERE OrderId>0 AND CustomerId=10
AND OrderDate>(SELECT max(OrderDate)+30 FROM tbl INNER JOIN #tmp ON id=OrderId)
ORDER BY OrderDate;
-- now list all found entries of tbl:
SELECT * FROM tbl WHERE EXISTS (SELECT 1 FROM #tmp WHERE id=OrderId)
#tinka shows how to use CTEs to do the trick, and the new windowed functions (for 2012 and later) are probably the best answer. There is also the option, assuming you do not have a very large data set, to use a recursive CTE.
Example:
declare #customerid int = 10;
declare #temp table
(orderid int,
customerid int,
orderDate date
);
insert into #temp values (1, 10, '07/05/2014')
insert into #temp values (2, 10, '07/15/2014')
insert into #temp values (3, 11, '07/20/2014')
insert into #temp values (4, 11, '08/20/2014')
insert into #temp values (5, 11, '09/21/2014')
insert into #temp values (6, 10, '09/23/2014')
insert into #temp values (7, 10, '10/15/2014')
insert into #temp values (8, 10, '10/30/2014');
with datefilter AS
(
SELECT row_number() OVER(PARTITION BY CustomerId ORDER BY OrderDate) as RowId,
OrderId,
CustomerId,
OrderDate,
DATEADD(day, 30, OrderDate) as FilterDate
from #temp
WHERE CustomerId = #customerid
)
, firstdate as
(
SELECT RowId, OrderId, CustomerId, OrderDate, FilterDate
FROM datefilter
WHERE rowId = 1
union all
SELECT datefilter.RowId, datefilter.OrderId, datefilter.CustomerId,
datefilter.OrderDate, datefilter.FilterDate
FROM datefilter
join firstdate
on datefilter.CustomerId = firstdate.CustomerId
and datefilter.OrderDate > firstdate.FilterDate
WHERE NOT EXISTS
(
SELECT 1 FROM datefilter betweens
WHERE betweens.CustomerId = firstdate.CustomerId
AND betweens.orderdate > firstdate.FilterDate
AND datefilter.orderdate > betweens.orderdate
)
)
SELECT * FROM firstdate
Using MSSQL, I am trying to get some information from a journal where one event happens directly after another event.
So what I am effectively aiming for, is to get a row number partitioned by a TransactionID, and then I need the last 2 rows (last 2 row number) for EACH transactionID (Ordered by a TxnDate field). There could be any number of rows per TransactionID.
So I would get:
JnlId TxnId RowNum
5 10001 65
2 10001 66
10 10002 11
8 10002 12
5 10003 15
98 10003 16
Any ideas how I could achieve this as I am at a loss! The end game after this is to filter out the 'JnlId' field for a select few of IDs.
Bit of a back story. This customer thinks their staff is stealing, so I need to filter out when they are cancelling items directly before finishing off each transaction.
Try this, I added some extra rows to make dense rank more obvious:
Test data:
DECLARE #t table(JnlId int,TxnId int,RowNum int, TxnDate date)
INSERT #t values
(5, 10001,65, '2015-01-01'),
(2, 10001,66, '2015-01-02'),
(2, 10001,66, '2015-01-03'),
(2, 10001,66, '2015-01-04'),
(2, 10001,67, '2015-01-04'),
(2, 10001,67, '2015-01-04'),
(10,10002,11, '2015-01-03'),
(8, 10002,12, '2015-01-04'),
(5, 10003,15, '2015-01-05'),
(98,10003,16, '2015-01-06')
Query:
;WITH CTE AS
(
SELECT
DENSE_RANK() over(partition by txnID order by TxnDate desc) rn,
JnlId, TxnId, RowNum, TxnDate
FROM #t
)
SELECT JnlId, TxnId, RowNum, TxnDate FROM CTE
WHERE rn<=2
Result:
JnlId TxnId RowNum TxnDate
2 10001 66 2015-01-04
2 10001 67 2015-01-04
2 10001 67 2015-01-04
2 10001 66 2015-01-03
8 10002 12 2015-01-04
10 10002 11 2015-01-03
98 10003 16 2015-01-06
5 10003 15 2015-01-05
Instead of ordering in ascending order try descending order
select * from
(
select dense_rank() over(partition by transactionID Order by TxnDate Desc) Rn,*
from yourtable
) A
where rn<=2
Just order by RowNum descending and then select what has ROW_NUMBER less or equals 2
DECLARE #Table TABLE
(
JnlId INT
, TxnId INT
, RowNum INT
);
INSERT INTO #Table
(JnlId, TxnId, RowNum)
VALUES
(5, 10001, 65)
, (2, 10001, 66)
, (10, 10002, 11)
, (8, 10002, 12)
, (5, 10003, 15)
, (98, 10003, 16);
SELECT T.JnlId, T.TxnId, T.RowNum
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY TxnId ORDER BY RowNum DESC) AS RowNo, *
FROM #Table) AS T
WHERE T.RowNo <=2
i am using sql server 2008.
i am calculating envetory as FIFO method like in tally.
please go through
http://accountingexplained.com/financial/inventories/fifo-method
i have table as
create table #Stock
(
StoreId int,
ProductId int,
Transection_Date Date,
transectionType varchar(20),
Unit numeric(18,2),
UnitCost numeric(18,2)
)
insert into #Stock select 1,201, '2014-03-01', 'Beginning Inventory', 68, 14
insert into #Stock select 1,201,'2014-03-05', 'Purchase', 140, 15.50
insert into #Stock select 1,201,'2014-03-09', 'Issue', 94, 0
insert into #Stock select 1,201,'2014-03-11', 'Purchase', 40, 16
insert into #Stock select 1,201,'2014-03-16', 'Purchase', 68, 14
insert into #Stock select 1,201,'2014-03-20', 'Issue', 116, 0
insert into #Stock select 1,201,'2014-03-29', 'Issue', 62, 0
select * from #Stock
drop table #Stock
i am looking sql function or store procedure which will accept parameter
fromDate,toDate and sorteId
and display as given format
How about:
--DROP TABLE #Stock
create table #Stock
(
Transection_Date Date,
transectionType varchar(20),
Unit numeric(18,2),
UnitCost numeric(18,2)
)
--Mar 1 Beginning Inventory 68 units # $15.00 per unit
--5 Purchase 140 units # $15.50 per unit
--9 Sale 94 units # $19.00 per unit
--11 Purchase 40 units # $16.00 per unit
--16 Purchase 78 units # $16.50 per unit
--20 Sale 116 units # $19.50 per unit
--29 Sale 62 units # $21.00 per unit
insert into #Stock select '2014-03-01', 'Beginning Inventory', 68, 15
insert into #Stock select '2014-03-05', 'Purchase', 140, 15.50
insert into #Stock select '2014-03-09', 'Sale', 94, 19
insert into #Stock select '2014-03-11', 'Purchase', 40, 16
insert into #Stock select '2014-03-16', 'Purchase', 78, 16.5
insert into #Stock select '2014-03-20', 'Sale', 116, 19.50
insert into #Stock select '2014-03-29', 'Sale', 62, 21.00
;WITH UnitsCTE
AS
(
-- GET Total Units Left
SELECT SUM(
CASE transectionType
WHEN 'Purchase' Then Unit
When 'Sale' THEN Unit * -1
ELSE Unit END) AS Units
FROM #Stock
), PurchaseCTE
AS
(
-- Get only purchases in reverse order
SELECT Unit, UnitCost, Transection_Date, ROW_NUMBER() OVER (ORDER BY Transection_Date DESC ) AS RN
FROM #Stock
WHERE transectionType <> 'Sale'
),
UnitCost
AS
(
-- Recursive CTE to get number of units left at each price
SELECT CASE WHEN Unit > UnitsCTE.Units THEN UnitsCTE.Units ELSE Unit END As Units, UnitCost
FROM PurchaseCTE
CROSS APPLY UnitsCTE
WHERE RN = 1
UNION ALL
SELECT CASE WHEN P1.Unit > (UnitsCTE.Units - (SELECT SUM(Unit) FROM PurchaseCTE P3 WHERE p3.RN < p1.RN))
THEN CASE WHEN (UnitsCTE.Units - (SELECT SUM(Unit) FROM PurchaseCTE P3 WHERE p3.RN < p1.RN)) < 0 THEN 0
ELSE (UnitsCTE.Units - (SELECT SUM(Unit) FROM PurchaseCTE P3 WHERE p3.RN < p1.RN)) END
ELSE P1.Unit END,
P1.UnitCost
FROM PurchaseCTE P1
INNER JOIN PurchaseCTE P2
ON P1.RN = P2.RN + 1
CROSS APPLY UnitsCTE
)
SELECT SUM(Units), SUM(UnitCost * Units) / SUM(Units) AS UnitCost, SUM(Units * UnitCost) AS TotalCost
FROM UnitCost
WHERE Units > 0