SQL to display pivoted data - sql

I have the following table:
and i want the following output displayed:
the above is basically the (quan*cst) for each day. Now I can acieve this by the following sql:
select t1.pid, isnull(b.m1,0) as day1sale, isnull(a.m2,0) as day2sale
from dbo.test1 t1
left join(select pid, sum(quan*cst) m1
from dbo.test1 where date='2017-05-01' group by pid) b on b.pid=t1.pid
left join (select pid, sum(quan*cst) m2
from dbo.test1 where date='2017-05-02' group by pid) a on a.pid=t1.pid
group by t1.pid,m2 ,m1
order by t1.pid
But i was wondering if there is a simpler way to do it without actually having to hard code the dates?
thanks in advance for the help!

Using a self join to get a list of distinct dates, the result set can be pivoted and the desired aggregates applied to each PID.
CREATE TABLE #TEMP_EXAMPLE
(
[DATE] DATE,
[ID] INT,
[PID] INT,
[QUAN] INT,
[CST] INT
)
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','1','1','2','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','2','2','6','2')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','3','3','5','1')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','4','1','1','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','5','3','3','1')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','6','4','4','7')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','7','1','7','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','8','5','2','8')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','9','6','5','6')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','10','2','8','2')
SELECT ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY [DATE]) AS ID,*
INTO #TEMP_DYNAMIC_DATES
FROM (SELECT DISTINCT [DATE] FROM #TEMP_EXAMPLE ) AS X
SELECT * FROM #TEMP_DYNAMIC_DATES
SELECT PID,ISNULL(DAY1SALE,0) AS DAY1SALE,ISNULL(DAY2SALE,0) AS DAY2SALE FROM (
SELECT PID,SUM([QUAN] * [CST]) AS X, INDIC FROM (
SELECT A.*,
CASE WHEN B.ID = 1 THEN 'DAY1SALE'
WHEN B.ID = 2 THEN 'DAY2SALE'
END AS INDIC
FROM #TEMP_EXAMPLE AS A
JOIN #TEMP_DYNAMIC_DATES AS B
ON A.DATE = B.DATE
) AS X
GROUP BY PID,INDIC) AS O
PIVOT(SUM(X) FOR INDIC IN([DAY1SALE],[DAY2SALE])) AS PT

Related

How to update only MAX column in SQL Server

I want to update the MAX value's status column with static values in SQL Server:
Script to generate sample data:
CREATE TABLE A
(
seq INT,
TrnId NVARCHAR(MAX),
Status NVARCHAR(10)
)
INSERT INTO A VALUES (1,'A1','A')
INSERT INTO A VALUES (2,'A1','A')
INSERT INTO A VALUES (3,'A1','A')
INSERT INTO A VALUES (4,'A1','P')
INSERT INTO A VALUES (1,'B1','A')
INSERT INTO A VALUES (2,'B1','A')
INSERT INTO A VALUES (3,'B1','A')
INSERT INTO A VALUES (4,'B1','P')
CREATE TABLE #temp
(
TrnId NVARCHAR(MAX)
)
INSERT INTO #temp VALUES ('A1')
INSERT INTO #temp VALUES ('B1')
I have TrnId In #temp table and I want to update only the MAX values column for both TrnId as A1 and B1 with status = 'A'
An example without a CTE:
UPDATE A SET A.Status = 'A'
FROM #temp T
INNER JOIN (SELECT TrnId, MAX(seq) as MaxSeq FROM A GROUP BY TrnId) M ON M.TrnId = T.TrnId
INNER JOIN A ON A.TrnId = T.TrnId AND A.seq = M.MaxSeq
One method uses an updatable CTE:
with toupdate as (
select a.*,
row_number() over (partition by trnid order by status desc) as seqnum
from a
)
update toupdate
set status = 'A'
from toupdate join
#temp t
on toupdate.trnid = t.trnid
where seqnum = 1;

Select only oldest unique records

The below code should
Grab multiple values from multiple tables across 2 databases
but as I attempted to implement
T-SQL select rows by oldest date and unique category solution to an issue I encountered an error where the final line of my code would say "Incorrect syntax near ')'."
--Create Table #tmp2(FK_clientids varchar(50))
--Create table #tmp (phonenums varchar(50))
Delete from #tmp2
Delete from #tmp
Use Database2
INSERT INTO #tmp2
SELECT fk_clientid
FROM DM_ClientApplicants
where DM_ClientApplicants.FK_ApplicationID in (39155)
Use Database2
INSERT INTO #tmp
Select phonenum2 from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select PhoneNum1 from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select PhoneNum2 from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select PhoneNum3 from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select Partnerphonehome from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select Partnerphonemobile from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
INSERT INTO #tmp
Select Partnerphonework from DM_PhoneNumbers
where FK_ApplicationID in
(
Select FK_clientIDs from #tmp2
)
Use Database1
Select PhoneNum,sourcetable,c.FK_ApplicationID,SolRef,DT.Subject,dt.CreatedDate
from (select PhoneNum,sourcetable,c.FK_ApplicationID,SolRef,DT.Subject,dt.CreatedDate,
row_number() over(partition by OrderNO order by dt.CreatedDate desc) rn
from Dial D
join Database2.dbo.DM_PhoneNumbers P on PhoneNum collate Latin1_General_CI_AS = PhoneNum1
join Database2.dbo.DM_ClientApplicants C on P.FK_ApplicationID = C.FK_ClientID
join Database2.dbo.DM_Sol S on C.FK_ApplicationID = S.FK_ApplicationID
join Database2.dbo.DM_ApplicationDetails AD on AD.FK_ApplicationID = S.FK_ApplicationID
join Database2.dbo.Tasks DT on DT.FK_ApplicationID = S.FK_ApplicationID
where PhoneNum in
(Select phonenums from #tmp)
UPDATE: So the bracket near "RN" is open, but if I try to close it the rest of the statement is not understood, anyone know why?
The end of your sql should be:
Use Database1
Select PhoneNum,sourcetable,FK_ApplicationID,SolRef,Subject,CreatedDate
from
(
select PhoneNum,sourcetable,c.FK_ApplicationID,SolRef,DT.Subject,dt.CreatedDate
,row_number() over(partition by OrderNO order by dt.CreatedDate desc) rn
from Dial D
join Database2.dbo.DM_PhoneNumbers P on PhoneNum collate Latin1_General_CI_AS = PhoneNum1
join Database2.dbo.DM_ClientApplicants C on P.FK_ApplicationID = C.FK_ClientID
join Database2.dbo.DM_Sol S on C.FK_ApplicationID = S.FK_ApplicationID
join Database2.dbo.DM_ApplicationDetails AD on AD.FK_ApplicationID = S.FK_ApplicationID
join Database2.dbo.Tasks DT on DT.FK_ApplicationID = S.FK_ApplicationID
where PhoneNum in
(
Select phonenums from #tmp
)
)a -- add

Selection One Entry Only As Non Zero In SQl Select

I have a scenario where I have to select multiple rows from table, I have multiple rows of one record but with different status,
at times I have two identical rows with identical data for status < for that case I canted to select Non zero for the first occurrence and set 0 for the remaining occurrences.
Below is the Image to show and I have marked strike-out and marked 0 for the remaining occurrence.
And body could suggest better SQL Query:
Here is the Query: I am getting zero value for status 1 for ID =1 but I need to show first as regular and then 0 if that status repeats again.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
SELECT CASE WHEN Temp.Status = 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (SELECT * FROM #Temp) Temp
DROP TABLE #Temp
Here is the result:
You might modify your inner select using Row_Number() and set price to Zero for RowNumber > 1.
SELECT CASE WHEN Temp.RowNumber > 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (
SELECT *,Row_Number() over (PARTITION by ID,Status ORDER BY ID,Date) AS 'RowNumber'
FROM #Temp
) Temp
Order by ID,Date
You can try this:
;WITH DataSource AS
(
SELECT RANK() OVER (PARTITION BY [ID], [ItemName], [Price], [Status] ORDER BY Date) AS [RankID]
,*
FROM #Temp
)
SELECT [ID]
,[ItemName]
,IIF([RankID] = 1, [Price], 0)
,[Status]
,[Date]
FROM DataSource
ORDER BY [ID]
,[Date]
Here is the output:
please try this below code . it is working for me.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
select *,case when a.rn=1 and status!=2 then price else 0 end as price from
(select *,ROW_NUMBER() over(partition by status,date order by date asc) rn from #Temp) a
order by ItemName asc
You can do this with UNION:
SELECT * FROM #Temp t
WHERE NOT EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
UNION ALL
SELECT ID, ItemName, 0 as Price, status, date
WHERE EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
Or subquery:
SELECT CASE
WHEN (SELECT COUNT(*)
FROM #Temp
WHERE t.id = id and t.status = status
and t.date > date) > 1 THEN 0 ELSE price END as NewPrice, t.*
FROM #Temp t
Or possibly RANK() function:
SELECT CASE
WHEN RANK() OVER (PARTITION BY id, status ORDER BY date) > 1
THEN 0 ELSE Price END,
t.*
FROM #Temp t

Deleting records that are similar with previous one SQL Server

I am looking for a query which fetches me the data that is different compared to the previous row,
A sample code (with table creation and data)
create table #temp
(id int, eid int, name char(10),estid int, ecid int, epid int, etc char(5) )
insert into #temp values (1,1,'a',1,1,1,'a')
insert into #temp values (2,1,'a',1,1,1,'a')
insert into #temp values (3,1,'a',2,1,1,'a')
insert into #temp values (4,1,'a',1,1,1,'a')
insert into #temp values (5,1,'a',1,1,1,'a')
insert into #temp values (6,1,'a',1,2,1,'a')
insert into #temp values (7,1,'a',1,1,1,'a')
insert into #temp values (8,1,'a',2,1,1,'a')
insert into #temp values (9,1,'a',1,1,1,'a')
insert into #temp values (10,1,'a',1,1,1,'a')
insert into #temp values (11,2,'a',1,1,1,'a')
insert into #temp values (12,2,'a',1,1,1,'a')
insert into #temp values (13,2,'a',2,1,1,'a')
insert into #temp values (14,2,'a',1,1,1,'a')
insert into #temp values (15,2,'a',1,1,1,'a')
insert into #temp values (16,2,'a',1,2,1,'a')
insert into #temp values (17,2,'a',1,1,1,'a')
insert into #temp values (18,2,'a',2,1,1,'a')
insert into #temp values (19,2,'a',1,1,1,'a')
insert into #temp values (20,2,'a',1,1,1,'a')
I tried with some ways of getting the data as the way that i expected
SELECT * INTo #Temp_Final
FROM #temp
WHERE #temp.%%physloc%%
NOT IN (SELECT Min(b.%%physloc%%)
FROM #temp b
GROUP BY eid,name,estid,ecid,epid,etc)
ORDER BY id
SELECT * FROM #temp WHERE id not in (SELECT id FROM #Temp_Final) ORDER BY id
But i wasn't getting the result as i expected...
This is how the result needs to be
select * from #temp where id in (1,3,4,6,7,8,9,11,13,14,16,17,18,19)
You can do this with a simple self-join and appropriate comparison:
select t.*
from #temp t left outer join
#temp tprev
on t.id = tprev.id + 1
where tprev.id is null or
t.name <> tprev.name or
t.estid <> tprev.estid or
t.ecid <> tprev.ecid or
t.epid <> tprev.epid or
t.etc <> tprev.etc;
This assumes that the ids are sequential with no gaps. If the ids are not, you can get the previous id using a correlated subquery or the lag() function.
Your title says "delete" but the question seems to just want the list of such rows. You can phrase this as a delete query if you need to.
For SQL Server 2012 (SQL Fiddle)
WITH CTE
AS (SELECT *,
LAG(eid) OVER (ORDER BY id) AS prev_eid,
LAG(name) OVER (ORDER BY id) AS prev_name,
LAG(estid) OVER (ORDER BY id) AS prev_estid,
LAG(ecid) OVER (ORDER BY id) AS prev_ecid,
LAG(epid) OVER (ORDER BY id) AS prev_epid,
LAG(etc) OVER (ORDER BY id) AS prev_etc
FROM #temp)
DELETE FROM CTE
WHERE EXISTS (SELECT eid,
name,
estid,
ecid,
epid,
etc
INTERSECT
SELECT prev_eid,
prev_name,
prev_estid,
prev_ecid,
prev_epid,
prev_etc)
select
t.id,
t.eid,
t.name,
t.estid,
t.ecid,
t.epid,
t.etc
from #temp t
left join #temp d
on d.id = t.id-1
and d.eid = t.eid
and d.name = t.name
and d.estid = t.estid
and d.ecid = t.ecid
and d.epid = t.epid
and d.etc = t.etc
where d.id is null

How to pivot column values of the below table?

TableA:
Brand Product
------------------
A X
A XX
A XXX
B Y
B YY
C Z
I need data as shown in Table below:
A B C
-------------------
X Y Z
XX YY NULL
XXX NULL NULL
How to do that in Sql Server 2008 ?
I dont beleive a PIVOT is what you are looking for here.
From what I can see you are looking at using the entries in order to generate the rows?
Also, PIVOTs make use of aggregate functions, so I cant see this happening.
What you can try, is something like
DECLARE #Table TABLE(
Brand VARCHAR(10),
Product VARCHAR(10)
)
INSERT INTO #Table SELECT 'A','X '
INSERT INTO #Table SELECT 'A','XX'
INSERT INTO #Table SELECT 'A','XXX'
INSERT INTO #Table SELECT 'B','Y'
INSERT INTO #Table SELECT 'B','YY'
INSERT INTO #Table SELECT 'C','Z'
;WITH Vals AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Brand ORDER BY (SELECT NULL)) RID
FROM #Table
)
, RIDs AS (
SELECT DISTINCT
RID
FROM Vals
)
SELECT vA.Product [A],
vB.Product [B],
vC.Product [C]
FROM RIDs r LEFT JOIN
Vals vA ON r.RID = vA.RID
AND vA.Brand = 'A' LEFT JOIN
Vals vB ON r.RID = vB.RID
AND vB.Brand = 'B' LEFT JOIN
Vals vC ON r.RID = vC.RID
AND vC.Brand = 'C'
I know it is a late entry, but here is a different approach to solve it:
DECLARE #Table TABLE(Brand VARCHAR(10), Product VARCHAR(10))
INSERT INTO #Table SELECT 'A','X '
INSERT INTO #Table SELECT 'A','XX'
INSERT INTO #Table SELECT 'A','XXX'
INSERT INTO #Table SELECT 'B','Y'
INSERT INTO #Table SELECT 'B','YY'
INSERT INTO #Table SELECT 'C','Z'
SELECT [A],[B],[C] FROM (
SELECT row_number() over (partition by brand order by product) rn,
Product, brand FROM #table
) as p
PIVOT(
MAX(product) for Brand in ([A],[B],[C])
)as pvt