SQL Server : row over - sql-server

I have two tables one that maintain the assets and the other which maintains the sub assets:
Table 1: assethdr
assetid
0000000002
0000000003
and
Table 2: assetdet
assetsubid assetid
0000000001 0000000002
0000000002 0000000002
0000000003 0000000002
0000000001 0000000003
0000000001 0000000109
0000000002 0000000109
0000000003 0000000109
0000000004 0000000109
0000000005 0000000109
I did this query:
WITH cte_assets
as
(SELECT
CASE WHEN ROW_NUMBER() OVER(PARTITION BY h.assetid ORDER BY f.assetsubid) = 1
THEN 'BA-'+LTRIM(RTRIM(h.CpnyId))+'-'+right(LTRIM(h.AssetId),5)+'-'+'0001' ELSE '' END as [Business Asset Number]
, 'BA'+
+'-'+RIGHT(LTRIM(RTRIM(ltrim(rtrim(f.cpnyid)))),3)
+'-'+
RIGHT(f.assetid,5)+'-'+RIGHT(f.assetsubid,4)as [Component Asset ID*]
FROM pssfaassets f
INNER JOIN PSSFAAssetsHdr h
ON f.AssetId=h.assetid
AND h.AssetId LIKE '%0000000002'
--GROUP BY h.cpnyid,h.AssetId,f.AssetSubId
)
SELECT * FROM cte_assets
WHERE [Business Asset Number]<>[Component Asset ID*]
ORDER BY [Component Asset ID*],[Business Asset Number]
but I don't get the right result, which should be :
Rownum Business Asset Number rownum2 Component Asset ID*
1 BA-613-00002-0001 1 BA-613-00002-0002
1 2 BA-613-00002-0003
2 BA-607-00109-001 1 BA-607-00109-0002
2 2 BA-607-00109-0003
2 3 BA-607-00109-0004
2 4 BA-607-00109-0005

Lets make some test data: I added the cpnyid (guessing based on your output) for both the header and detail records.
DECLARE #assethdr TABLE
(
assetid varchar(20),
CpnyId varchar(20)
)
INSERT INTO #assethdr
( assetid, CpnyId )
VALUES
('0000000002', '613'),
('0000000003', '605'),
('0000000109', '607');
DECLARE #assetdet TABLE
(
assetsubid varchar(20),
assetid varchar(20),
CpnyId varchar(20)
);
INSERT INTO #assetdet
( assetsubid, assetid, CpnyId )
VALUES
('0000000001', '0000000002', '613'),
('0000000002', '0000000002', '613'),
('0000000003', '0000000002', '613'),
('0000000001', '0000000003', '605'),
('0000000001', '0000000109', '607'),
('0000000002', '0000000109', '607'),
('0000000003', '0000000109', '607'),
('0000000004', '0000000109', '607'),
('0000000005', '0000000109', '607');
The query is similar, but I added the row number to the output:
WITH cte_assets
as
(SELECT
ROW_NUMBER() OVER (PARTITION BY h.assetid ORDER BY f.assetsubid) AS RN,
CASE WHEN ROW_NUMBER() OVER(PARTITION BY h.assetid ORDER BY f.assetsubid) = 2
THEN 'BA-'+LTRIM(RTRIM(h.CpnyId))+'-'+right(LTRIM(h.AssetId),5)+'-'+'0001' ELSE '' END as [Business Asset Number]
, 'BA'+
+'-'+RIGHT(LTRIM(RTRIM(ltrim(rtrim(f.cpnyid)))),3)
+'-'+
RIGHT(f.assetid,5)+'-'+RIGHT(f.assetsubid,4)as [Component Asset ID*]
FROM #assetdet f
INNER JOIN #assethdr h
ON f.AssetId=h.assetid
--AND h.AssetId LIKE '%0000000002'
--GROUP BY h.cpnyid,h.AssetId,f.AssetSubId
)
Now with the addition of the row number, you are trying to bypass the first match it seems (from your expected output):
SELECT (RN - 1) AS RowNum, [Business Asset Number], [Component Asset ID*]
FROM cte_assets
WHERE [RN] != 1
ORDER BY [Component Asset ID*],[Business Asset Number]
Here is the output:
RowNum Business Asset Number Component Asset ID*
1 BA-607-00109-0001 BA-607-00109-0002
2 BA-607-00109-0003
3 BA-607-00109-0004
4 BA-607-00109-0005
1 BA-613-00002-0001 BA-613-00002-0002
2 BA-613-00002-0003

Related

SQL unpivot of multiple columns

I would like the following wide table to be unpivotted but only where a user has a true value against the field, along with the appropriate date.
Current State:
CUSTOMER_ID
First_Party_Email
Third_Party_Email
First_Party_Email_Date
Third_Party_Email_Date
40011111
1
1
2021-01-22 04:38:00.000
2021-01-17 06:38:00.000
50022222
NULL
1
NULL
2021-01-18 04:38:00.000
80066666
1
NULL
2021-01-24 05:38:00.000
NULL
_______________
_______________________
_______________________
_______________________________
_______________________________
Required State:
Customer_ID
Type
Value
Date
40011111
First_Party_Email
1
22/01/2021 04:38
40011111
Third_Party_Email
1
17/01/2021 06:38
50022222
Third_Party_Email
1
18/01/2021 04:38
80066666
First_Party_Email
1
24/01/2021 05:38
_______________________________________________________________________
Associated query to create table and my attempt that doesn't work:
create table Permissions_Obtained
(Customer_ID bigint
,First_Party_Email bit
,Third_Party_Email bit
,First_Party_Email_Date datetime
,Third_Party_Email_Date datetime
)
insert into Permissions_Obtained
(Customer_ID
,First_Party_Email
,Third_Party_Email
,First_Party_Email_Date
,Third_Party_Email_Date
)
VALUES
(40011111, 1, 1, '2021-01-22 04:38', '2021-01-17 06:38'),
(50022222, NULL, 1, NULL, '2021-01-18 04:38'),
(80066666, 1, NULL, '2021-01-24 05:38', null)
select *
from Permissions_Obtained
select
customer_id, Permission
from Permissions_Obtained
unpivot
(
GivenPermission
for Permission in (
First_Party_Email, Third_Party_Email
)
) unpiv1,
unpivot
(
GivenPermissionDate
for PermissionDate in (
First_Party_Email_Date, Third_Party_Email_Date
)
) unpiv2
where GivenPermission = 1
--drop table Permissions_Obtained
Any help would be massively appreciated. TIA
You cannot have multiple unpivots at the same time. Instead you can use Cross Apply or Inner join or union, union all or kind of joins depending on your requirement. I have added a sample answer for this using join and unpivot.
SELECT
unpvt.Customer_ID
, [Type]
, ISNULL(po.First_Party_Email ,po.Third_Party_Email) AS [Value]
,CASE WHEN unpvt.Type = 'First_Party_Email' THEN po.First_Party_Email_Date
ELSE po.Third_Party_Email_Date
END AS [Date]
FROM
(
SELECT
Customer_ID, First_Party_Email , Third_Party_Email
FROM Permissions_Obtained
) p
UNPIVOT
( [Value] FOR [Type] IN
(First_Party_Email , Third_Party_Email )
)AS unpvt
INNER JOIN Permissions_Obtained [po]
on [po].Customer_ID = unpvt.Customer_ID
When un-pivoting multiple columns, CROSS APPLY (VALUES is often the easiest and most effective solution.
It creates a virtual table per-row of the previous table, and therefore un-pivots it into separate rows.
SELECT
p.Customer_Id,
v.[Type],
v.Value,
v.Date
FROM Permissions_Obtained p
CROSS APPLY (VALUES
('First_Party_Email', p.First_Party_Email, p.First_Party_Email_Date),
('Third_Party_Email', p.Third_Party_Email, p.Third_Party_Email_Date)
) v([Type], Value, Date)
where v.Value IS NOT NULL;

T-SQL join query using distinct values from second table

I know this question might sound like a duplicate, but I've been through every question I could find; though it's still possible it might be a duplicate of a question I might have missed.
I have what at surface value appears to be a trivial requirement but no matter how I script it out there's always some caveat that's just not working. I've tried GROUP, DISTINCT, JOIN, aggregate functions, etc.
Scenario:
PRIMARYTABLE contains a set of campaigns and SECONDARYTABLE contains the dates on which campaigns were run. There can be multiple runs per campaign and I've included a SUBKEY for each run.
Requirement:
I need to be able to get the most recently run campaigns into a list so the user can more easily select from the campaigns that get run the most frequent.
PRIMARYTABLE
KEYCOLUMN INFOCOLUMN
100000 Test 1
100001 Test Campaign
100002 Test Image 2
100003 Test Img
100004 Image Test
100005 Test
100006 Test Image 3
100007 Test Image 4
100008 Test Image 5
100009 Image Comparison Test 2
100010 Testing
100011 Test Fields
100012 Test 5
100013 test
SECONDARYTABLE
KEYCOLUMN SUBKEY DATECOLUMN
100000 100000 2017-06-02 04:09:57.593
100001 100001 2017-06-19 12:09:54.093
100001 100002 2017-06-27 10:51:14.140
100004 100003 2017-06-27 12:33:47.747
100006 100004 2017-06-28 10:29:53.387
100007 100005 2017-06-28 10:36:23.710
100008 100006 2017-06-29 22:31:03.790
100009 100007 2017-06-29 23:07:52.870
100009 100010 2017-10-04 16:05:40.583
100009 100011 2017-10-04 16:09:55.470
100011 100008 2017-09-08 14:02:28.017
100012 100009 2017-09-11 16:17:23.870
100013 100012 2017-11-07 16:55:55.403
100013 100013 2017-11-08 15:37:16.430
Below is somewhat of an idea of more or less what I'm after.
SELECT DISTINCT( a.[INFOCOLUMN] )
FROM [PRIMARYTABLE] a
INNER JOIN [SECONDARYTABLE] b ON ( a.[KEYCOLUMN] = b.[KEYCOLUMN] )
ORDER BY a.[DATECOLUMN]
Here's hoping for a Homer Simpson "Doh!" moment once I see how it's supposed to be done.
Much appreciated.
the most recently run campaigns >> use row_number() over(.. order by ... DESC)
that get run the most frequent >> use count(*) over(partition by ..)
Using window functions row_number() over() and count() over() enables selection by row of data that is "most recent" and ordering by "most frequent". Note that the DESCending order of dates brings about "recent" = 1.
select
p.*, s.*
from PRIMARYTABLE p
inner join (
select KEYCOLUMN, SUBKEY, DATECOLUMN
, row_number() over(partition by KEYCOLUMN order by DATECOLUMN DESC) recent
, count(*) over(partition by KEYCOLUMN) frequency
from SECONDARYTABLE
) s on p.KEYCOLUMN = s.KEYCOLUMN and s.recent = 1
order by s.frequency DESC, p.INFOCOLUMN
You can try this:
DECLARE #PRIMARYTABLE TABLE
(
[KEYCOLUMN] INT
,[INFOCOLUMN] VARCHAR(24)
);
DECLARE #SECONDARYTABLE TABLE
(
[KEYCOLUMN] INT
,[SUBKEY] INT
,[DATECOLUMN] DATETIME2
);
INSERT INTO #PRIMARYTABLE ([KEYCOLUMN], [INFOCOLUMN])
VALUES (100000, 'Test 1')
,(100001, 'Test Campaign')
,(100002, 'Test Image 2')
,(100003, 'Test Img')
,(100004, 'Image Test')
,(100005, 'Test')
,(100006, 'Test Image 3')
,(100007, 'Test Image 4')
,(100008, 'Test Image 5')
,(100009, 'Image Comparison Test 2')
,(100010, 'Testing')
,(100011, 'Test Fields')
,(100012, 'Test 5')
,(100013, 'test');
INSERT INTO #SECONDARYTABLE ([KEYCOLUMN], [SUBKEY], [DATECOLUMN])
VALUES (100000, 100000, '2017-06-02 04:09:57.593')
,(100001, 100001, '2017-06-19 12:09:54.093')
,(100001, 100002, '2017-06-27 10:51:14.140')
,(100004, 100003, '2017-06-27 12:33:47.747')
,(100006, 100004, '2017-06-28 10:29:53.387')
,(100007, 100005, '2017-06-28 10:36:23.710')
,(100008, 100006, '2017-06-29 22:31:03.790')
,(100009, 100007, '2017-06-29 23:07:52.870')
,(100009, 100010, '2017-10-04 16:05:40.583')
,(100009, 100011, '2017-10-04 16:09:55.470')
,(100011, 100008, '2017-09-08 14:02:28.017')
,(100012, 100009, '2017-09-11 16:17:23.870')
,(100013, 100012, '2017-11-07 16:55:55.403')
,(100013, 100013, '2017-11-08 15:37:16.430');
SELECT a.[INFOCOLUMN]
,b.[DATECOLUMN]
FROM #PRIMARYTABLE A
CROSS APPLY
(
SELECT TOP 1 [DATECOLUMN]
FROM #SECONDARYTABLE B
WHERE A.[KEYCOLUMN] = B.[KEYCOLUMN]
ORDER BY [DATECOLUMN] DESC
) b;
It will give you the last execution of each campaign. You can filter then by date or ORDER BY and get TOP N from the final query.
Or you can use ROW_NUMBER:
WITH DataSource AS
(
SELECT A.[INFOCOLUMN]
,B.[DATECOLUMN]
,ROW_NUMBER() OVER (PARTITION BY A.[KEYCOLUMN] ORDER BY B.[KEYCOLUMN]) AS [RowID]
FROM #PRIMARYTABLE A
INNER JOIN #SECONDARYTABLE B
ON A.[KEYCOLUMN] = B.[KEYCOLUMN]
)
SELECT [INFOCOLUMN]
,[DATECOLUMN]
FROM DataSource
WHERE [RowID] = 1;
try this, it will return the list of campaigns in most frequent order of use. Note campaigns never run wont appear in your list. in this case you will to do a left join
SELECT a.[INFOCOLUMN]
FROM [PRIMARYTABLE] a
/* left */ JOIN [SECONDARYTABLE] b ON a.[KEYCOLUMN] = b.[KEYCOLUMN]
group BY a.[infocolumn]
order by max(datecolumn) desc
here is a stub i did to test it
select 10000 id,'Campain A' cname into #a1 union all
select 10002,'Campain B' union all
select 10004,'Campain C' union all
select 10009,'Campain E'
select 10000 id,'20170101' thedate into #a2 union all
select 10000,'20170102' union all
select 10009,'20170103' union all
select 10002,'20170104' union all
select 10004,'20170105' union all
select 10000,'20170201' union all
select 10000,'20170302' union all
select 10009,'20170403' union all
select 10002,'20170104' union all
select 10004,'20170205' union all
select 10000,'20170101' union all
select 10004,'20170302' union all
select 10000,'20170103' union all
select 10002,'20170404' union all
select 10002,'20170105'
select #a1.cname
from #a1 join #a2 on #a1.id = #a2.id
group by #a1.cname
order by max(thedate) desc

SSRS:How to return count of events per day for Month

I have a table with the following information
ID,DateTime,EventType
1,6/5/2013 9:35:00,B
1,6/5/2013 9:35:24,A
2,6/5/2013 9:35:36,B
3,6/5/2013 9:36:11,D
2,6/5/2013 9:39:16,A
3,6/5/2013 9:40:48,B
4,7/5/2013 9:35:19,B
4,7/5/2013 9:35:33,A
5,7/5/2013 9:35:53,B
5,7/5/2013 9:36:06,D
6,7/5/2013 9:39:39,A
7,7/5/2013 9:40:28,B
8,8/5/2013 9:35:02,A
7,8/5/2013 9:35:08,A
8,8/5/2013 9:35:29,B
6,8/5/2013 9:36:39,B
I need to count how many times each day an event changed state as long as the time between states was less than 30 seconds over the time period.
Basically I am looking for the following result set
6/5/2013 | 1
7/5/2013 | 2
8/5/2013 | 1
I've tried several different types of queries, but nothing works. I am using SQL Server Reporting Services 2008.
declare #t table (ID int,[DateTime] datetime ,EventType varchar);
insert #t values
(1,'6/5/2013 9:35:00','B'),
(1,'6/5/2013 9:35:24','A'),
(2,'6/5/2013 9:35:36','B'),
(3,'6/5/2013 9:36:11','D'),
(2,'6/5/2013 9:39:16','A'),
(3,'6/5/2013 9:40:48','B'),
(4,'7/5/2013 9:35:19','B'),
(4,'7/5/2013 9:35:33','A'),
(5,'7/5/2013 9:35:53','B'),
(5,'7/5/2013 9:36:06','D'),
(6,'7/5/2013 9:39:39','A'),
(7,'7/5/2013 9:40:28','B'),
(8,'8/5/2013 9:35:02','A'),
(7,'8/5/2013 9:35:08','A'),
(8,'8/5/2013 9:35:29','B'),
(6,'8/5/2013 9:36:39','B');
--select * from #t order by ID, DateTime;
with cte as (
select *, cast([DateTime] as date) the_date, row_number() over (partition by ID order by DateTime) row_num
from #t
)
select c1.the_date, count(1)
from cte c1
join cte c2
on c2.ID = c1.ID
and c2.row_num = c1.row_num + 1
where datediff(S,c1.DateTime, c2.DateTime) < 30
group by c1.the_date
order by c1.the_date;
Try this:
select CONVERT(VARCHAR(10), a.DateTime, 103) [Date], count(a.ID) Count from Table a
inner join Table b on a.ID = b.ID
where DATEDIFF(second,a.DateTime,b.DateTime) between 1 and 29 and a.ID = b.ID
and Cast(a.DateTime as Date) = Cast(b.DateTime as date)
group by CONVERT(VARCHAR(10), a.DateTime, 103)

Exact Claim Count for each rows using pivot with join in SQL Server 2012

By executing the below SQL 2012 Query, I got the following output
declare
#ticketstatus nvarchar(20) = 'To Be Allocated'
SELECT m1.ClaimSource, m1.Insurance, n1.[Claim Count], n1.[Claim Value],
ISNULL(m1.[0-30],0) [0-30],
ISNULL(m1.[31-60],0) [31-60],
ISNULL(m1.[61-90],0) [61-90],
ISNULL(m1.[91-120],0) [91-120],
ISNULL(m1.[121-210],0) [121-210],
ISNULL(m1.[210++],0) [210++]
FROM (
SELECT *
FROM (
SELECT ClaimSource, Insurance, CurrentBalance _Count, AgeBucket
FROM ClaimMaster
) m
PIVOT (
COUNT(_Count)
FOR AgeBucket IN ([0-30],[31-60],[61-90],[91-120],[121-210],[210++])
) n
) m1
join
(SELECT Insurance, COUNT(Insurance) [Claim Count], SUM(CurrentBalance) [Claim Value] FROM ClaimMaster
WHERE (TicketStatus = #ticketstatus OR #ticketstatus IS NULL)
GROUP BY Insurance) n1
ON m1.Insurance = n1.Insurance
ORDER BY n1.[Claim Count] DESC
How can I get the correct output for Claim Count, Claim Value on the 4, 5 & 6 rows. Instead of showing full claim count, it should show the respective claim count filter by Claim Source such as Claim Count should be 2 and appropriate Claim Value.
Can anyone help me on this.
Add claimsource and join on that as well?
declare
#ticketstatus nvarchar(20) = 'To Be Allocated'
SELECT m1.ClaimSource, m1.Insurance, n1.[Claim Count], n1.[Claim Value],
ISNULL(m1.[0-30],0) [0-30],
ISNULL(m1.[31-60],0) [31-60],
ISNULL(m1.[61-90],0) [61-90],
ISNULL(m1.[91-120],0) [91-120],
ISNULL(m1.[121-210],0) [121-210],
ISNULL(m1.[210++],0) [210++]
FROM (
SELECT *
FROM (
SELECT ClaimSource, Insurance, CurrentBalance _Count, AgeBucket
FROM ClaimMaster
) m
PIVOT (
COUNT(_Count)
FOR AgeBucket IN ([0-30],[31-60],[61-90],[91-120],[121-210],[210++])
) n
) m1
join
(SELECT ClaimSource, Insurance, COUNT(Insurance) [Claim Count], SUM(CurrentBalance) [Claim Value] FROM ClaimMaster
WHERE (TicketStatus = #ticketstatus OR #ticketstatus IS NULL)
GROUP BY ClaimSource, Insurance) n1
ON m1.Insurance = n1.Insurance and m1.ClaimSource = n1.ClaimSource
ORDER BY n1.[Claim Count] DESC

LASt 6 records of the output of the stored procedure

The following is the stored procedure and "I want to fetch the LATEST SIX
INVOICES FOR EACH CUSTOMER"
THERE COULD BE MORE INVOICES FOR EACH CUSTOMER BUT I HAVE TO FETCH ONLY
WHICH ARE LATEST 6 INVOICES.
ALTER PROCEDURE [dbo].[SCA_M_CUSTSOINV_REFRESH]
#COMP_CD NVARCHAR(20)='',
#USER_CD NVARCHAR(20)='',
#USER_TYPE NVARCHAR(1)=''
AS
SET NOCOUNT ON
DECLARE #SLSHIST_DATE NVARCHAR(10)
SELECT
#SLSHIST_DATE = CONVERT(NVARCHAR(10), DATEADD(MONTH,-SLSHIST_MTH,dbo.[GetCountryDate]()),120)
FROM SET_MASTER
WITH SUBQUERY AS
(SELECT
ROW_NUMBER() OVER (PARTITION BY A.CUST_CD ORDER BY C.INV_KEY DESC) "ROW_ID",
A.CUST_CD,C.SO_KEY "TXN_KEY",
C.INV_NO, C.INV_KEY, C.INV_DT, C.INV_STATUS, C.NET_TTL_TAX AS INV_AMT
FROM
(SELECT DIST_CD, SLSMAN_CD, CUST_CD FROM T_CA_SLSMANCUST
WHERE DIST_CD = #COMP_CD AND SLSMAN_CD = #USER_CD) A
INNER JOIN TXN_INVOICE C ON C.CUST_CD=A.CUST_CD
AND C.INV_DT >= #SLSHIST_DATE
)
SELECT
CUST_CD, TXN_KEY, INV_NO, INV_KEY, INV_DT, INV_STATUS, INV_AMT,
CASE ROW_ID WHEN 1 THEN 'Y' ELSE 'N' END "LAST_INV"
FROM SUBQUERY
ORDER BY CUST_CD,INV_KEY
You are getting ROW_ID by ROW_NUMBER() OVER (PARTITION BY A.CUST_CD ORDER BY C.INV_KEY DESC) and the last invoice is the one with ROW_ID = 1 so don't you just need to add WHERE ROW_ID <= 6 as below?
SELECT
CUST_CD, TXN_KEY, INV_NO, INV_KEY, INV_DT, INV_STATUS, INV_AMT,
CASE ROW_ID WHEN 1 THEN 'Y' ELSE 'N' END "LAST_INV"
FROM SUBQUERY
WHERE ROW_ID <= 6
ORDER BY CUST_CD,INV_KEY
SELECT TOP 6 * FROM invoices ORDER BY date DESC

Resources