SQL Update query product cart - sql

ID ProductId MemberId SessionId CreatedOn Quantity
62 1 2 2012-09-11 1
63 2 2 2012-09-11 1
64 1 0 agzdeoqubwokfme05wwmne55 2012-09-11 1
65 3 0 agzdeoqubwokfme05wwmne55 2012-09-11 1
I have above table and I need to make one procedure.
My scenario is without login add item to cart and when you login merge all items.
I will pass two parameter in procedure #MemberId (Login Member Id), #SessionID
And I want out put table like below.
ID ProductId MemberId SessionId CreatedOn Quantity
62 1 2 2012-09-11 2
63 2 2 2012-09-11 1
65 3 2 2012-09-11 1
One product merges with another product and makes quantity 2. And that row should be gone.

Assuming SQL SERVER 2005 or above
CREATE TABLE #T (ID INT , ProductId INT, MemberId INT, SessionId VARCHAR(100), CreatedOn DATETIME, Quantity INT)
INSERT INTO #T SELECT 62,1 ,2 ,' ','2012-09-11',1
INSERT INTO #T SELECT 63, 2,2, ' ','2012-09-11',1
INSERT INTO #T SELECT 64, 1,0,'agzdeoqubwokfme05wwmne55','2012-09-11',1
INSERT INTO #T SELECT 65, 3,0,'agzdeoqubwokfme05wwmne55','2012-09-11',1
;With CTE AS
(SELECT
ID
,ProductId
,MemberId = MAX(MemberId) OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
,SessionID
,CreatedOn = CONVERT(VARCHAR(10),MAX(CreatedOn) OVER(PARTITION BY ProductID ORDER bY(SELECT 1)),20)
,Quantity = SUM(Quantity) OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
,Rn = ROW_NUMBER() OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
FROM #T)
SELECT ID,ProductId,MemberId,SessionID,CreatedOn,Quantity FROM CTE WHERE Rn = 1
DROP TABLE #T
will give the result as
ID ProductId MemberId SessionID CreatedOn Quantity
62 1 2 2012-09-11 2
63 2 2 2012-09-11 1
65 3 0 agzdeoqubwokfme05wwmne55 2012-09-11 1
Finally if you want to update the table, the here you go
UPDATE #T
SET
#T.ID = c.ID
,#T.ProductId =c.ProductId
,#T.MemberId = c.MemberId
,#T.SessionID = c.SessionID
,#T.CreatedOn = c.CreatedOn
,#T.Quantity = c.Quantity
FROM #T
INNER JOIN CTE c
ON #T.ID = c.ID
WHERE c.Rn = 1
The result is
ID ProductId MemberId SessionId CreatedOn Quantity
62 1 2 2012-09-11 2
63 2 2 2012-09-11 1
64 1 0 agzdeoqubwokfme05wwmne5 2012-09-11 1
65 3 0 agzdeoqubwokfme05wwmne55 2012-09-11 1
The complete query is
;With CTE AS
(SELECT
ID
,ProductId
,MemberId = MAX(MemberId) OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
,SessionID
,CreatedOn = CONVERT(VARCHAR(10),MAX(CreatedOn) OVER(PARTITION BY ProductID ORDER bY(SELECT 1)),20)
,Quantity = SUM(Quantity) OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
,Rn = ROW_NUMBER() OVER(PARTITION BY ProductID ORDER bY(SELECT 1))
FROM #T)
UPDATE #T
SET
#T.ID = c.ID
,#T.ProductId =c.ProductId
,#T.MemberId = c.MemberId
,#T.SessionID = c.SessionID
,#T.CreatedOn = CONVERT(VARCHAR(10),c.CreatedOn,20)
,#T.Quantity = c.Quantity
FROM #T
INNER JOIN CTE c
ON #T.ID = c.ID
WHERE c.Rn = 1
SELECT * FROM #T
DROP TABLE #T
For Any Version of SQL
UPDATE #T
SET
#T.ID = c.ID
,#T.ProductId =c.ProductId
,#T.MemberId = c.MemberId
,#T.SessionID = c.SessionID
,#T.CreatedOn = c.CreatedOn
,#T.Quantity = c.Quantity
FROM #T
INNER JOIN (SELECT t.ID,t.ProductID,t.MemberId,t.SessionId,t.CreatedOn,x.Quantity
FROM #T t
JOIN (
SELECT
ID = MIN(ID)
,ProductID
,MemberId = MAX(MemberId)
,CreatedOn = MAX(CreatedOn)
,Quantity = SUM(Quantity)
FROM #T
GROUP BY ProductID
)X
ON t.ID =X.ID) c
ON #T.ID = c.ID
SELECT * FROM #T
DROP TABLE #T

SELECT ProductID,
max(MemberId),
max(CreatedOn),
sum(Quantity)
FROM theTable
WHERE SessionID=<id> or MemberID=<id>
GROUP BY ProductID

Updating may not be the optimum solution, it may be better to delete all the records and insert new ones.
Anyhow you need to do something like this if you want to update and then delete the extra ones.
Assuming ID is the unique key here. Here is complete logic, read carefully
DECLARE #Temp1 TABLE
(
--datafields same AS your table
)
DECLARE #Temp2 TABLE
(
--datafields same AS your table
)
INSERT INTO #Temp1
SELECT ID,
ProductID,
MemberId,
SessionId,
CreatedOn,
Quantity
FROM theTable
WHERE SessionID= #SessionID or MemberID= #MemberID
UPDATE a
SET SessionID = #SessionID , MemberID= #MemberID
FROM #Temp1 AS a
--WHERE SessionID= #SessionID OR MemberID= #MemberID
INSERT INTO #Temp2
SELECT MAX(ID),
ProductID,
max(MemberId),
MAX(SessionId),
max(CreatedOn),
sum(Quantity)
FROM #Temp1
GROUP BY ProductID
UPDATE a
SET a.MemberId = b.MemberId ,a.SessionId=b.SessionId ,a.CreatedOn=b.CreatedOn,a.Quantity=b.Quantity
FROM YourTable AS a
INNER JOIN #Temp2 AS b
ON a.ID=b.ID
DELETE FROM YourTable
WHERE ID IN ( SELECT ID
FROM #Temp1 AS ta
WHERE NOT EXISTS ( SELECT 1
FROM #Temp2 AS tb
WHERE ta.ID = tb.ID ) )

Related

Create episode for each value with new Begin and End Dates

This is in reference to below Question
Loop through each value to the seq num
But now Client want to see the data differently and started a new thread for this question.
below is the requirement.
This is the data .
ID seqNum DOS Service End Date
1 1 1/1/2017 1/15/2017
1 2 1/16/2017 1/16/2017
1 3 1/17/2017 1/21/2017
1 4 1/22/2017 2/13/2017
1 5 2/14/2017 3/21/2017
1 6 2/16/2017 3/21/2017
Expected outPut:
ID SeqNum DOSBeg DOSEnd
1 1 1/1/2017 1/30/2017
1 2 1/31/2017 3/1/2017
1 3 3/2/2017 3/31/2017
For each DOSBeg, add 29 and that is DOSEnd. then Add 1 to DOSEnd (1/31/2017) is new DOSBeg.
Now add 29 to (1/31/2017) and that is 3/1/2017 which is DOSEnd . Repeat this untill DOSend >=Max End Date i.e 3/21/2017.
Basically, we need episode of 29 days for each ID.
I tried with this code and it is giving me duplicates.
with cte as (
select ID, minDate as DOSBeg,dateadd(day,29,mindate) as DOSEnd
from #temp
union all
select ID,dateadd(day,1,DOSEnd) as DOSBeg,dateadd(day,29,dateadd(day,1,DOSEnd)) as DOSEnd
from cte
)
select ID,DOSBeg,DOSEnd
from cte
OPTION (MAXRECURSION 0)
Here mindate is Minimum DOS for this ID i.e. 1/1/2017
I came up with below logic and this is working fine for me. Is there any better way than this ?
declare #table table (id int, seqNum int identity(1,1), DOS date, ServiceEndDate date)
insert into #table
values
(1,'20170101','20170115'),
(1,'20170116','20170116'),
(1,'20170117','20170121'),
(1,'20170122','20170213'),
(1,'20170214','20170321'),
(1,'20170216','20170321'),
(2,'20170101','20170103'),
(2,'20170104','20170118')
select * into #temp from #table
--drop table #data
select distinct ID, cast(min(DOS) over (partition by ID) as date) as minDate
,row_Number() over (partition by ID order by ID, DOS) as SeqNum,
DOS,
max(ServiceEndDate) over (partition by ID)as maxDate
into #data
from #temp
--drop table #StartDateLogic
with cte as
(select ID,mindate as startdate,maxdate
from #data
union all
select ID,dateadd(day,30,startdate) as startdate,maxdate
from cte
where maxdate >= dateadd(day,30,startdate))
select distinct ID,startdate
into #StartDateLogic
from cte
OPTION (MAXRECURSION 0)
--final Result set
select ID
,ROW_NUMBER() over (Partition by ID order by ID,StartDate) as SeqNum
,StartDate
,dateadd(day,29,startdate) as EndDate
from #StartDateLogic
You were on the right track wit the recursive cte, but you forgot the anchor.
declare #table table (id int, seqNum int identity(1,1), DOS date, ServiceEndDate date)
insert into #table
values
(1,'20170101','20170115'),
(1,'20170116','20170116'),
(1,'20170117','20170121'),
(1,'20170122','20170213'),
(1,'20170214','20170321'),
(1,'20170216','20170321'),
(2,'20170101','20170103'),
(2,'20170104','20170118')
;with dates as(
select top 1 with ties id, seqnum, DOSBeg = DOS, DOSEnd = dateadd(day,29,DOS)
from #table
order by row_number() over (partition by id order by seqnum)
union all
select t.id, t.seqNum, DOSBeg = dateadd(day,1,d.DOSEnd), DOSEnd = dateadd(day,29,dateadd(day,1,d.DOSEnd))
from dates d
inner join #table t on
d.id = t.id and t.seqNum = d.seqNum + 1
)
select *
from dates d
where d.DOSEnd <= (select max(dateadd(month,1,ServiceEndDate)) from #table where id = d.id)
order by id, seqNum

Query to get the list of Addresses that have AddressType one else AddressType two?

Consider the folowing table
Id PersonId Address AddressTypeId
--------------------------------------------------------------------
1 1 AI1P1T1 1
2 1 AI2P1T2 2
3 2 AI3P2T2 2
I want to write a query to print the list of Addresses of Persons who have AddressType =1 or AddressTypeId=2 and
When person has AddressType =1 then select it,
else select person with AddressType =2
Expected result:
Address
--------------
AI1P1T1
AI3P2T2
Good day,
Please check if this solve your needs:
/***************************** DDL+DML */
drop table if exists T;
create table T(Id int,PersonId int, [Address] nvarchar(10), AddressTypeId int)
INSERT T(Id,PersonId, [Address], AddressTypeId)
values
(1,1,'AI1P1T1',1),
(2,1,'AI2P1T2',2),
(3,2,'AI3P2T2',2)
GO
select * from T
GO
/***************************** Solution */
With MyCTE as (
select *, ROW_NUMBER() OVER (partition by PersonId order by AddressTypeId) as RN
from T
)
select [Address]
from MyCTE
where
AddressTypeId in (1,2) -- if there can be only positive numbers then you can use "< 3"
and RN = 1
GO
You can try this also using joins:
select t1.PersonId,t1.Address from #T t1
inner join (select personid,min(AddressTypeId)atype from #T
group by PersonId )x
on x.atype=t1.AddressTypeId and x.PersonId=t1.PersonId
I would write a subquery to make ROW_NUMBER by window function, then use MAX in the main query.
SELECT
PersonId, MAX(Address) Address
FROM
(SELECT
PersonId,
(CASE
WHEN ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY PersonId) = 1
THEN Address
END) Address
FROM
T
WHERE
AddressTypeId IN (1,2)
) t1
GROUP BY
PersonId
sqlfiddle
[Results]:
| PersonId | Address |
+----------+---------+
| 1 | AI1P1T1 |
| 2 | AI3P2T2 |
Here's the top 1 with ties trick:
select top 1 * with ties
from yourtable
order by row_number() over (partition by PersonId order by AddressTypeId)
This will also work for versions <2012, and can return every field
You could use an union between the result for the result for only 1, only 2 and 1 when 1 and 2
select Address
from my_table m
Inner join (
select PersonId , count(distinct distinct AddressTypeId)
from my_table
where AddressTypeId in (1, 2)
group by PersonId
having count(distinct AddressTypeId) = 2
) t on t.personId = m.personId andm.AddressTypeId = 1
UNION
select Address
from my_table m
Inner join (
select PersonId , count(distinct distinct AddressTypeId)
from my_table
where AddressTypeId in ( 2)
group by PersonId
having count(distinct AddressTypeId) = 1
) t on t.personId = m.personId andm.AddressTypeId = 2
UNION
select Address
from my_table m
Inner join (
select PersonId , count(distinct distinct AddressTypeId)
from my_table
where AddressTypeId in ( 1)
group by PersonId
having count(distinct AddressTypeId) = 1
) t on t.personId = m.personId andm.AddressTypeId = 1
Try this one
select personId, last_value(Address) over(partition by personId order by AddressTypeId) as Address
from table
--use the where statement optionally
--where AddressTypeId in (1,2);

How to join tables, concatenate some data

I have two tables:
1. indexes and quantity of indexes
2. indexes and quantity of indexes with specified boxcodes. Boxcode is a number of box, which box contains indexes.
1. input table 1
item_id quantity
1 10
2 15
3 5
1 5
1 5
2 5
3 5
sum:
1 - 20
2 - 20
3 - 10
2. input table 2
item_id quantity boxcode
1 3 abc
2 2 abc
1 8 def
3 10 ghi
1 9 ghi
2 9 def
2 8 ghi !!!!!!!
1 item_id once on 1 boxcode
I want to get result:
3. result
item_id quantity boxcodes
1 10 abc/3, def/7
2 15 abc/2, def/9, ghi/4
3 5 ghi/5
1 5 def/1, ghi/4
1 5 ghi/5
2 5 ghi/4 !!!!!!!!
3 5 ghi/5
Records from table 1 must be in the same order.
I have no idea how it can be done.
Any suggestion?
CREATE TABLE #input1
(
rownum int,
item_id int,
quantity int
)
CREATE TABLE #input2
(
item_id int,
quantity int,
boxcode varchar(10)
)
INSERT INTO #input1 VALUES (1,1,10)
INSERT INTO #input1 VALUES (2,2,15)
INSERT INTO #input1 VALUES (3,3,5)
INSERT INTO #input1 VALUES (4,1,5)
INSERT INTO #input1 VALUES (5,1,5)
INSERT INTO #input1 VALUES (6,2,5)
INSERT INTO #input1 VALUES (7,3,5)
INSERT INTO #input2 VALUES (1,3, 'abc')
INSERT INTO #input2 VALUES (2,2, 'abc')
INSERT INTO #input2 VALUES (1,8, 'def')
INSERT INTO #input2 VALUES (3,10, 'ghi')
INSERT INTO #input2 VALUES (1,9, 'ghi')
INSERT INTO #input2 VALUES (2,9, 'def')
INSERT INTO #input2 VALUES (2,8, 'ghi')
select * from #input1
select * from #input2
drop table #input1
drop table #input2
result
Thanks,
Weird, but it works:
;WITH rec1 AS (
SELECT rownum,
item_id,
1 as q,
1 as [Level],
quantity
from #input1
UNION ALL
SELECT r.rownum,
r.item_id,
1,
[Level] + 1,
i.quantity
FROM rec1 r
INNER JOIN #input1 i
ON r.rownum = i.rownum AND r.item_id = i.item_id
WHERE [Level] < i.quantity
), rec2 AS (
SELECT boxcode,
item_id,
1 as q,
1 as [Level],
quantity
from #input2
UNION ALL
SELECT r.boxcode,
r.item_id,
1,
[Level] + 1,
i.quantity
FROM rec2 r
INNER JOIN #input2 i
ON r.boxcode = i.boxcode AND r.item_id = i.item_id
WHERE [Level] < i.quantity
), cte1 AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY item_id, rownum) as rn
FROM rec1
), cte2 AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY item_id, boxcode) as rn
FROM rec2
), final AS (
SELECT c1.rownum,
c1.item_id,
c1.quantity,
c2.boxcode+'/'+CAST(SUM(c2.q) as nvarchar(10)) as boxcodes
FROM cte1 c1
INNER JOIN cte2 c2
ON c1.item_id = c2.item_id and c1.rn = c2.rn
GROUP BY c1.rownum, c1.item_id, c1.quantity, c2.boxcode
)
SELECT DISTINCT
f.rownum,
f.item_id,
f.quantity,
STUFF((
SELECT ', '+f1.boxcodes
FROM final f1
WHERE f1.rownum = f.rownum
AND f1.item_id = f.item_id
AND f1.quantity = f.quantity
FOR XML PATH('')
),1,2,'') boxcodes
FROM final f
Output for dataset you have provided:
rownum item_id quantity boxcodes
1 1 10 abc/3, def/7
2 2 15 abc/2, def/9, ghi/4
3 3 5 ghi/5
4 1 5 def/1, ghi/4
5 1 5 ghi/5
6 2 5 ghi/4
7 3 5 ghi/5
The main idea is to spread quantity in both tables for a small parts 1. Than add row number, then join and get result.
A solution (but it's totally based on gofr1's answer, to be honest !), to simplify a bit, would be to create a Numbers table, with as many numbers as you want.
CREATE TABLE Numbers(Number INT PRIMARY KEY);
INSERT Numbers
SELECT TOP 1000 ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_columns;
That would just avoid the 2 recursive CTEs.
You could then use the same logic as gofr1 :
with rec1 AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY item_id, rownum) as rn,
rownum,
item_id,
case when quantity = 0 then 0 else 1 end as q,
quantity
from #input1
join Numbers n on n.Number <= quantity
)
, rec2 AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY item_id, boxcode) as rn,
boxcode,
item_id,
case when quantity = 0 then 0 else 1 end as q,
quantity
from #input2
join Numbers n on n.Number <= quantity
),
final AS (
SELECT c1.rownum,
c1.item_id,
c1.quantity,
c2.boxcode+'/'+CAST(SUM(c2.q) as nvarchar(10)) as boxcodes
FROM rec1 c1
INNER JOIN rec2 c2
ON c1.item_id = c2.item_id and c1.rn = c2.rn
GROUP BY c1.rownum, c1.item_id, c1.quantity, c2.boxcode
),
stuffed as (
SELECT
distinct rownum,
f.item_id,
f.quantity,
STUFF((
SELECT ', '+f1.boxcodes
FROM final f1
WHERE f1.rownum = f.rownum
AND f1.item_id = f.item_id
AND f1.quantity = f.quantity
FOR XML PATH('')
),1,2,'') boxcodes
FROM final f
group by item_id, quantity, boxcodes, rownum)
select *
from stuffed
order by rownum

How to merge two particular rows into single row and reaming rows are same using stored procedure SQL Server 2012

I have data like this. first row of Id 1 from particular time period and second row of id 1 is another time period. so now want to combined id and name which are same in the two time periods reaming are same.if there is no orders from that time period its should be display 0 or null.
Id Name Qty Price
----------------------
1 Rose 4 540
1 Rose 1 640
2 Lilly 5 550
2 Lilly 18 360
3 Grand 2 460
3 Grand 10 360
4 lotus 0 0
4 Lotus 9 580
now I want data like this..
Id Name Qty Price
4 540
1 rose
1 640
5 550
2 Lilly
18 360
2 460
3 Grand
10 360
0 0
4 Lotus
9 580
This is my procedure
create PROCEDURE [dbo].[Sp_Orders]
(
#Startdate varchar(30),
#Enddate varchar(30),
#Startdate1 varchar(30),
#Enddate1 varchar(30)
)
--[Sp_Orders] '03/01/2016','03/15/2016','02/01/2016','02/28/2016'
AS
BEGIN
---First Duration----
SELECT DISTINCT
op.ProductId as id, op.Price as Prc,
sc.SubCategoryName as ScName,
COUNT(op.ProductId) AS Qty,
ROUND(SUM(op.Price * op.Quantity), 0) AS Revenue,
FROM
orderdetails od
INNER JOIN
(SELECT DISTINCT
Orderid, Productid, ProductFeatures, Price, Quantity
FROM
OrderProducts) op ON od.Orderid = op.Orderid
INNER JOIN
products p ON p.productid = op.productid
INNER JOIN
subcategory sc ON sc.subcategoryid = p.subcategoryid
WHERE
CONVERT(datetime, CONVERT(varchar(50), od.DeliveryDate, 101)) BETWEEN #Startdate AND #Enddate
GROUP BY
op.ProductID, op.Price, sc.SubCategoryName
---Second Duration----
SELECT DISTINCT
op.ProductID AS id, op.Price AS Prc,
sc.SubCategoryName AS ScName,
COUNT(op.ProductId) AS Qty,
ROUND(SUM(op.Price * op.Quantity), 0) AS Revenue,
FROM
orderdetails od
INNER JOIN
(SELECT DISTINCT
Orderid, Productid, ProductFeatures, Price, Quantity
FROM
OrderProducts) op ON od.Orderid = op.Orderid
INNER JOIN
products p ON p.productid = op.productid
INNER JOIN
subcategory sc ON sc.subcategoryid = p.subcategoryid
WHERE
CONVERT(datetime, CONVERT(varchar(50),od.DeliveryDate,101)) BETWEEN #Startdate1 AND #Enddate1
GROUP BY
op.ProductID, op.Price, sc.SubCategoryName
END
From what I understood from your Question and Comments:
Schema for your case
SELECT * INTO #TAB FROM(
SELECT 1 ID, 'ROSE' NAME, 4 QTY, 540 PRICE
UNION ALL
SELECT 1 , 'ROSE' , 1 , 640
UNION ALL
SELECT 2 , 'LILLY' , 5 , 550
UNION ALL
SELECT 2 , 'LILLY' , 18 ,360
UNION ALL
SELECT 3 , 'GRAND' , 2 , 460
UNION ALL
SELECT 3 , 'GRAND' , 10 ,360
UNION ALL
SELECT 4 , NULL,NULL,NULL
UNION ALL
SELECT 4 , 'LOTUS' , 9 , 580
) AS A
And the Logic to display is as below
SELECT CASE WHEN SNO=1 THEN CAST(ID AS VARCHAR(250)) ELSE '' END ID,
CASE WHEN SNO=1 THEN ISNULL(NAME,'') ELSE '' END NAME,ISNULL(Qty,0)Qty
,ISNuLL(Price,0)Price FROM (
SELECT ROW_NUMBER() Over(partition by Name, Id ORDER BY (SELECT 1)) SNO
,ID, NAME , Qty, Price, ID AS ID2 FROM #TAB
)AS A
ORDER BY ID2, NAME DESC
Try this from your Procedure. And may need to do type cast based on your actual datatypes
CREATE PROCEDURE [DBO].[SP_ORDERS]
(
#STARTDATE VARCHAR(30),
#ENDDATE VARCHAR(30),
#STARTDATE1 VARCHAR(30),
#ENDDATE1 VARCHAR(30)
)
--[SP_ORDERS] '03/01/2016','03/15/2016','02/01/2016','02/28/2016'
AS
BEGIN
SELECT CASE WHEN SNO=1 THEN CAST(ID AS VARCHAR(250)) ELSE '' END ID,CASE WHEN SNO=1 THEN ISNULL(SCNAME,'') ELSE '' END NAME,ISNULL(QTY,0)QTY,ISNULL(REVENUE,0)PRICE FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY SCNAME, ID ORDER BY (SELECT 1)) SNO, ID, SCNAME , QTY, REVENUE, ID AS ID2 FROM (
SELECT DISTINCT OP.PRODUCTID AS ID,OP.PRICE AS PRC,SC.SUBCATEGORYNAME AS SCNAME,COUNT(OP.PRODUCTID) AS QTY, ROUND(SUM(OP.PRICE * OP.QUANTITY), 0) AS REVENUE
FROM ORDERDETAILS OD INNER JOIN
(SELECT DISTINCT ORDERID,PRODUCTID,PRODUCTFEATURES,PRICE,QUANTITY FROM ORDERPRODUCTS ) OP ON OD.ORDERID=OP.ORDERID
INNER JOIN PRODUCTS P ON P.PRODUCTID=OP.PRODUCTID
INNER JOIN SUBCATEGORY SC ON SC.SUBCATEGORYID=P.SUBCATEGORYID
WHERE CONVERT(DATETIME,CONVERT(VARCHAR(50),OD.DELIVERYDATE,101)) BETWEEN #STARTDATE AND #ENDDATE
GROUP BY OP.PRODUCTID,OP.PRICE,SC.SUBCATEGORYNAME
---SECOND DURATION----
UNION ALL --ADDED NOW
SELECT DISTINCT OP.PRODUCTID AS ID,OP.PRICE AS PRC,SC.SUBCATEGORYNAME AS SCNAME,COUNT(OP.PRODUCTID) AS QTY, ROUND(SUM(OP.PRICE * OP.QUANTITY), 0) AS REVENUE
FROM ORDERDETAILS OD INNER JOIN
(SELECT DISTINCT ORDERID,PRODUCTID,PRODUCTFEATURES,PRICE,QUANTITY FROM ORDERPRODUCTS ) OP ON OD.ORDERID=OP.ORDERID
INNER JOIN PRODUCTS P ON P.PRODUCTID=OP.PRODUCTID
INNER JOIN SUBCATEGORY SC ON SC.SUBCATEGORYID=P.SUBCATEGORYID
WHERE CONVERT(DATETIME,CONVERT(VARCHAR(50),OD.DELIVERYDATE,101)) BETWEEN #STARTDATE1 AND #ENDDATE1
GROUP BY OP.PRODUCTID,OP.PRICE,SC.SUBCATEGORYNAME
)
AS A
)B
ORDER BY ID2, NAME
END
Based on your sample data i have given this Out put but if the data is inconsistent it may not give accurate results if you see the Expected Output it gives exact same
Declare #Table1 TABLE
(Id VARCHAR(10), Name varchar(5),Qty VARCHAR(10), Price varchar(10))
;
INSERT INTO #Table1
(Id, Name,Qty, Price)
VALUES
(1, 'Rose',4, 540),
(1, 'Rose',1, 640),
(2, 'Lilly',5, 550),
(2, 'Lilly',18, 360),
(3, 'Grand',2, 460),
(3, 'Grand',10, 360),
(4,'Lotus',0,0),
(4, 'Lotus',9, 580)
;
SCRIPT
;WITH CTE AS (
Select
CASE WHEN RN = 1 THEN ID ELSE NULL END ID,
CASE WHEN RN = 1 THEN Name ELSE NULL END NAME,
Qty,
Price
from (
select
Id,
Name,
Qty,
Price,
ROW_NUMBER()OVER(PARTITION BY ID,NAME ORDER BY NAME)RN
FROM
#Table1)T)
Select CASE WHEN RN = 2 THEN T.Id ELSE '' END ID,
CASE WHEN RN = 2 THEN T.Name ELSE '' END Name,
CASE WHEN RN IN (1,3) THEN ISNULL(T.Qty,0) ELSE '' END qty,
CASE WHEN RN IN (1,3) THEN ISNULL(T.Price,0) ELSE '' END qty from (
Select
T.ID,
T.NAME,
c.Qty,
C.Price,
ROW_NUMBER()OVER(PARTITION BY T.ID,T.NAME ORDER BY T.NAME)RN
from #Table1 T
INNER JOIN CTE C
ON T.Id = C.ID
AND T.Name = C.NAME
OR (T.Qty = C.Qty OR T.Price = C.Price ))T
WHERE T.RN <> 4

How to select data rows into columns w/out knowing all values

Below is a table I have with some order details.
OrderID TypeID Amount
11148 1 900
11148 7 30
11148 6 75
12506 3 100
12506 4 60
16845 1 30
Is it possible to return something like this:
OrderID TypeID1 Amount1 TypeID2 Amount2 TypeID3 Amount3
11148 1 900 7 30 6 75
12506 3 100 4 60 null null
16845 1 30 null null null null
I want to get results like this so I can join into another result set with other order information but I can only have one row per ID. I've been trying with a Pivot but it seems I need to know all the possible results for TYPEID and have that many columns instead of just the 3 for TYPEID and 3 for AMOUNT that I'm looking for.
Below is the Pivot table I know how to get to work but this is not desired because then I have columns for each ID type but I would rather have those in the rows too.
SELECT OrderID
,[1] as Amount1
,[2] as Amount2
,[3] as Amount3
,[4] as Amount4
,[5] as Amount5
,[6] as Amount6
,[7] as Amount7
FROM (
SELECT ORDERID, TYPEID, AMOUNT
FROM Order_Details
)x
PIVOT
(
MAX(AMOUNT)
FOR TYPEID in ([1],[2],[3],[4],[5],[6],[7])
)P
OrderID Amount1 Amount2 Amount3 Amount4 Amount5 Amount6 Amount7
11148 900 null null null null 75 30
12506 null null 100 60 null null null
16845 30 null null null null null null
the solution is to make a self outer join combined with row_number over partition like:
select t1.OrderId as OrderID1, t1.TypeID as TypeID1, t1.Amount as Amount1,
t2.TypeID as TypeID2, t2.Amount as Amount2,
t3.TypeID as TypeID3, t3.Amount as Amount3 from
(
SELECT OrderID, TypeID, Amount
FROM (
select OrderID , TypeID, Amount ,ROW_NUMBER() OVER (PARTITION BY OrderID order by OrderID) AS RN
from tt
)Sub
WHERE rn = 1) t1 left join
(
SELECT OrderID, TypeID, Amount
FROM (
select OrderID , TypeID, Amount ,ROW_NUMBER() OVER (PARTITION BY OrderID order by OrderID) AS RN
from tt
)Sub
WHERE rn = 2) t2 on t1.OrderID=t2.OrderID left join
(
SELECT OrderID, TypeID, Amount
FROM (
select OrderID , TypeID, Amount ,ROW_NUMBER() OVER (PARTITION BY OrderID order by OrderID) AS RN
from tt
)Sub
WHERE rn = 3) t3 on t1.OrderID=t3.OrderID;
live example
by using cross apply and Row_number we can achieve same result
declare #Table1 TABLE
(OrderID int, TypeID int, Amount int)
;
INSERT INTO #Table1
(OrderID, TypeID, Amount)
VALUES
(11148, 1, 900),
(11148, 7, 30),
(11148, 6, 75),
(12506, 3, 100),
(12506, 4, 60),
(16845, 1, 30)
;
;with CTE As (
select OrderID,[TypeID1],[TypeID2],[TypeID3] from (
Select OrderID,
val,
COL + CAST(ROW_NUMBER()OVER(PARTITION BY OrderID ORDER BY OrderID) AS VARCHAR(1))RN
FROM #Table1
CROSS APPLY (VALUES ('TypeID',TypeID))CS(Col,val))T
PIVOT (MAX(VAL) FOR RN IN ([TypeID1],[TypeID2],[TypeID3]))P )
,CTE2 AS (select OrderID,[Amount1],[Amount2],[Amount3] from (
Select OrderID,
val,
COL + CAST(ROW_NUMBER()OVER(PARTITION BY OrderID ORDER BY OrderID) AS VARCHAR(1))RN
FROM #Table1
CROSS APPLY (VALUES ('Amount',Amount))CS(Col,val))T
PIVOT (MAX(VAL) FOR RN IN ([Amount1],[Amount2],[Amount3]))P)
select c.OrderID,c.TypeID1,cc.Amount1,c.TypeID2,cc.Amount2,c.TypeID3,cc.Amount3 from CTE C
LEFT JOIN CTE2 CC
ON c.OrderID = cc.OrderID