WITH CTE1
AS (SELECT 'ABC' AS [Name],
4 AS [Call Count],
0 AS [Time_Slot]
UNION
SELECT 'XYX' AS [Name],
7 AS [Call Count],
1 AS [Time_Slot]
UNION
SELECT 'TRT' AS [Name],
6 AS [Call Count],
6 AS [Time_Slot]
UNION
SELECT 'DCFG' AS [Name],
8 AS [Call Count],
7 AS [Time_Slot]
UNION
SELECT 'DCS' AS [Name],
45 AS [Call Count],
18 AS [Time_Slot]
UNION
SELECT 'XYX' AS [Name],
45 AS [Call Count],
9 AS [Time_Slot]
)
SELECT *
FROM CTE1;
consider the output of the above code is
Name Call Count Time_Slot
ABC 4 0
DCFG 50 7
DCS 45 18
TRT 6 6
XYX 7 1
XYX 45 9
I wanted to output per user 24 hours data like below,
This data is for user DCFG likewise I wanted for each user (ABC, DCS, TRT, XYX)
Name Call Count Time_Slot
DCFG 0 0
DCFG 0 1
DCFG 0 2
DCFG 0 3
DCFG 0 4
DCFG 0 5
DCFG 0 6
DCFG 50 7
DCFG 0 8
DCFG 0 9
DCFG 0 10
DCFG 0 11
DCFG 0 12
DCFG 0 13
DCFG 0 14
DCFG 0 15
DCFG 0 16
DCFG 0 17
DCFG 0 18
DCFG 0 19
DCFG 0 20
DCFG 0 21
DCFG 0 22
DCFG 0 23
Now, what I have tried
it makes sense by using joins I'll not able to achieve what I wanted, by using cross join
I get all Time slots but its repeated 24-time slots entry for each user rows, for example
user 'XYX' CTE1 has Two Entries As Below
XYX 7 1
XYX 45 9
Cross Join create 24-time slot entry for above each row.
Can anyone suggest to me how I can achieve this, Thank you In advance
Use a (inline) tally, CROSS JOIN it to your user table (I assume you have one), and then LEFT JOIN that to your dataset above:
WITH Tally AS(
SELECT I
FROM(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23))V(I)),
UserTimes AS(
SELECT U.[Name],
T.I AS TimeSlot
FROM dbo.Users U
CROSS JOIN T)
SELECT YT.[Name],
C.CallCount,
YT.TimeSlot
FROM UserTimes UT
LEFT JOIN CTE1 C ON UT.[Name] = C.[Name]
AND UT.TimeSlot = C.TimeSlot;
Related
I have a TABLE with STR DNA DATA the following Table [DYS]
Id
DYS385
3
10-19
4
13-16
5
13-18
6
13-19
7
13-17
8
13-18
9
13-18
10
14-19
11
13-19
12
13-18
I am USING the following script to split the values of [DYS385]
select top 10 id,[DYS385],t.Value
from dys
OUTER APPLY(select * from string_split([DYS385],'-')) t
where dys385 is not null
Output
Id
DYS385
VALUE
3
10-19
10
3
10-19
19
4
13-16
13
4
13-16
16
5
13-18
13
5
13-18
18
6
13-19
13
6
13-19
19
7
13-17
13
7
13-17
17
I want to get for each Value, the Rank
example
10-19 => 10: Rank 1, 19: Rank 2
Desired results:
Id
DYS385
VALUE
RANK
3
10-19
10
1
3
10-19
19
2
4
13-16
13
1
4
13-16
16
2
5
13-18
13
1
5
13-18
18
2
6
13-19
13
1
6
13-19
19
2
7
13-17
13
1
7
13-17
17
2
Use an alternative string-split method, such as XML or Json that can return an ordinal position, such as:
create function dbo.SplitString(#string varchar(1000), #Delimiter varchar(10))
returns table
as
return(
select j.[value], 1 + Convert(tinyint,j.[key]) Seq
from OpenJson(Concat('["',replace(#string,#delimiter, '","'),'"]')) j
);
select value, Seq as [Rank]
from dbo.SplitString('10-19','-')
order by [Rank];
Example fiddle
Given this data:
CREATE TABLE dbo.Something(Id int, DYS385 varchar(10));
INSERT dbo.Something(Id, DYS385) VALUES (3 , '10-19'),
(4 , '13-16'), (5 , '13-18'), (6 , '13-19'),
(7 , '13-17'), (8 , '13-18'), (9 , '13-18'),
(10, '14-19'), (11, '13-19'), (12, '13-18');
Another way to make sure you rank the broken-up strings in the right order could be to use tricks like PARSENAME(), though this can be sensitive to strings lengths and whether a dot is valid within the data:
SELECT s.Id, s.DYS385, value = v.v, [rank] = ROW_NUMBER() OVER
(PARTITION BY s.Id ORDER BY c.c DESC)
FROM dbo.Something AS s
CROSS APPLY (VALUES(1),(2)) AS c(c)
CROSS APPLY (VALUES(PARSENAME(REPLACE(s.DYS385,'-','.'),c.c))) AS v(v)
ORDER BY s.Id, [rank];
Output:
Id
DYS385
value
rank
3
10-19
10
1
3
10-19
19
2
4
13-16
13
1
4
13-16
16
2
5
13-18
13
1
5
13-18
18
2
6
13-19
13
1
6
13-19
19
2
7
13-17
13
1
7
13-17
17
2
8
13-18
13
1
8
13-18
18
2
9
13-18
13
1
9
13-18
18
2
10
14-19
14
1
10
14-19
19
2
11
13-19
13
1
11
13-19
19
2
12
13-18
13
1
12
13-18
18
2
Example db<>fiddle
Split_string has an option to output this rank, called ordinal. Just add an extra parameter with the value of 1:
SELECT *FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ', 1);
That returns:
value ordinal
Lorem 1
ipsum 2
dolor 3
sit 4
amet. 5
In your case the query would be:
select top 10 id,[DYS385],t.* from dys OUTER APPLY(select * from string_split([DYS385],'-',1)) t where dys385 is not null
We can also make recursive split_string function which returns the rank of each item as follows
Link dbfiddle
Create function Split_Recursive(#string nvarchar(max),#delimiter as varchar(1)) returns Table
as
return(
with cte as(
select 1 N,
case when charindex(#delimiter,#string,1) =0 then #string else
substring(#string,1,-1+charindex(#delimiter,#string,1)) end [Found],
case when charindex(#delimiter,#string,1)=0 then #string else substring(#string,1+charindex(#delimiter,#string,1) ,len(#string))
end [MYSTRING]
union all
select 1+n,
case when charindex(#delimiter,[MYSTRING],1)=0 then [MYSTRING] else
substring([MYSTRING],1,-1+charindex(#delimiter,[MYSTRING],1)) end,substring([MYSTRING],1+charindex(#delimiter,[MYSTRING]),len([MYSTRING])) from cte
where charindex(#delimiter,[MYSTRING],1)>0),
cte2 as (select N,Found from cte
union select 1+t.N,Mystring from cte OUTER APPLY(select top 1 N from cte order by n desc)t where t.n=cte.n
)
select N Rank,Found from cte2
)
go
select * from dbo.Split_Recursive('12-16','-')
Output
Rank
Found
1
12
2
16
I'm trying to create a query that will return Total Claims reported in 0-3 days, 4-7 days, 8-14 days, and 15+
Select DATEDiff(DD,LossDate,DateReported) As TimeToReport,Count(ClaimId) As Num from LossRun
where PolicyNum='1234567890'
And PolTerm='201403'
Group By DATEDiff(DD,LossDate,DateReported)
order by DATEDiff(DD,LossDate,DateReported);
This is what i get
TimeToReport NumofClaims
0 5
1 3
2 1
3 4
4 3
5 2
6 2
7 2
8 1
12 1
13 1
14 2
15 2
48 1
52 1
107 1
121 1
147 1
533 1
Basically i want to see the total for 0-3, 4-7,8-14,and the rest,,,, timeToReport
You can try to use SUM with CASW WHEN
select
SUM(CASW WHEN TimeToReport <= 3 THEN NumofClaims ELSE 0 END) '0~3 day',
SUM(CASW WHEN TimeToReport >= 4 AND TimeToReport <=7 THEN NumofClaims END) '4-7 days',
SUM(CASW WHEN TimeToReport >= 8 AND TimeToReport <=14 THEN NumofClaims ELSE 0 END) '8-14 days',
SUM(CASW WHEN TimeToReport >= 15 THEN NumofClaims ELSE 0 END) '15+ day'
from (
Select DATEDiff(DD,LossDate,DateReported) As TimeToReport,Count(ClaimId) As Num
from LossRun
where PolicyNum='1234567890'
And PolTerm='201403'
Group By DATEDiff(DD,LossDate,DateReported)
) t
The most simple way is going to be by creating your own temp table which includes the min and max for each bucket and then joining to it.
declare #t table (OrderedID int, EmpID int, EffDate date, Salary money)
insert into #t
values
(1,1234,'20150101',1)
,(2,1234,'20160101',2)
,(3,1234,'20170101',8)
,(4,1234,'20180101',15)
,(1,2351,'20150101',17)
,(5,1234,'20190101',4)
,(5,1234,'20190101',2)
,(5,1234,'20190101',9)
declare #Bin table (MinVal int, MaxVal int)
insert into #Bin
values
(1,3)
,(4,6)
,(7,9)
,(10,15)
,(15,20)
,(20,25)
Select
B.MinVal,count(T.EmpID) as EmpsInBin
From #t T
inner join #Bin B on T.Salary between B.MinVal and B.MaxVal
group by B.MinVal
Output
MinVal EmpsInBin
1 3
4 1
7 2
10 1
15 2
This is the result of my first sql statement:
SELECT
count(*) countQuarter, Hour, Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter
which gives the following results:
Count Hour Quarter Rownum
497 0 15 1
842 0 30 2
1033 0 45 3
1120 0 60 4
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
I desire a result, where the column fullCount is the sum of the Count of the actual row and the next 3!
Count Hour Quarter Rownum Fullcount
497 0 15 1 3492
842 0 30 2 4230
1033 0 45 3 4655
1120 0 60 4 ...
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
How can this be done with grouping or analytical functions in SQL Server?
For SQL Server 2012, yes this can be done:
declare #t table ([Count] int,[Hour] int,[Quarter] int,Rownum int)
insert into #t([Count],[Hour],[Quarter],Rownum) values
(497 , 0 , 15 , 1 ),
(842 , 0 , 30 , 2 ),
(1033 , 0 , 45 , 3 ),
(1120 , 0 , 60 , 4 ),
(1235 , 1 , 15 , 5 ),
(1267 , 1 , 30 , 6 ),
(1267 , 1 , 45 , 7 ),
(1267 , 1 , 60 , 8 ),
(1267 , 2 , 15 , 9 ),
(1267 , 2 , 30 , 10 )
select *,SUM([Count]) OVER (
ORDER BY rownum
ROWS BETWEEN CURRENT ROW AND
3 FOLLOWING)
from #t
Here I'm using #t as your current result set - you may be able to adapt this into your current query or may have to place your current query in a CTE.
Unfortunately, the ROWS BETWEEN syntax is only valid on 2012 and later.
Tested the logical scenario and it works, but I don't have your data, so in your case it should look roughly like this:
;WITH CTE as (SELECT count(*) countQuarter,Hour,Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter)
SELECT *, CA.Fullcount
FROM CTE
CROSS APPLY (SELECT SUM(countQuarter) Fullcount FROM CTE C WHERE C.ID BETWEEN CTE.ID AND CTE.ID+3) CA
I would like to take biggest sequence number for each client Id (biggest sequence number will be calculated based on highest bank account balance).
This table has 100000 records.
Tables
ClientSeqTable T1
ClID SeqId
1 11
1 12
1 13
1 14
1 15
2 16
2 17
2 18
2 19
3 110
3 111
3 112
3 113
SeqBranchTable T2
SeqId BalID
11 1
12 2
13 3
14 4
15 5
16 6
17 7
18 8
19 9
110 10
111 11
112 12
113 13
Balancetable t3
BalID Balance
1 30000
2 26789
3 23456
4 12345
5 21234
6 12456
7 45632
8 23456
9 99999
10 12345
11 21234
12 12456
13 45632
Result would be
ClID SeqID Balance
1 1 30000
2 9 99999
3 4 45632
I have tried in this way but didn't work for me
SELECT RS.Investigationid,MAX(stt.sequenceid) 'SeqId', T.HighestBalance 'Balance'
FROM ClientSeqTable T1, SeqBranchTable T2, branbaltable t3,
( SELECT t1.clid ,MAX(T3.Balance) 'HighestBalance'
FROM ClientSeqTable T1, SeqBranchTable T2, branbaltable t3,
WHERE t1.seqid = T2.seqID
AND T2. balId= T3. balId
GROUP BY RS.Investigationid,stt.SequenceId
) T
WHERE T2.balId = T3.BalId
AND T1.SeqId = T2.SeqId
AND T3.HighestBalance = T2.balance
AND T1.clID = t.ClID
GROUP BY T1.ClID
With the above Query results are as below.
ClID SeqNu Bal
1 1 30000
1 2 30000
1 3 30000
1 4 30000
1 5 30000
2 3 99999
2 4 99999
2 1 99999
2 9 99999
3 2 45632
3 5 45632
3 3 45632
3 4 45632
If your able to use row_number function then should work:
select
*
from
(
select
t1.ClID, t1.SeqId, t3.Bal,
RowNumber = row_number() over (PARTITION BY t1.ClID order by t3.bal desc)
from
ClientSeqTable t1
inner join
SeqBranchTable t2 on t2.SeqId = t1.SeqId
inner join
Balancetable t3 on t3.BalID = t2.BalID
) t
where
t.RowNumber = 1
The important bit is row number partition by client id and then order by balance descending.
If you wanted to get your In-line on MAX you could do it this way
SELECT t1.ClID,
t1.SeqId,
t3.Balance
FROM ClientSeqTable t1
INNER JOIN SeqBranchTable t2
ON t2.SeqId = t1.SeqId
INNER JOIN Balancetable t3
ON t3.BalID = t2.BalID
INNER JOIN (SELECT Max(Balance) Bal,
t1.ClID
FROM ClientSeqTable t1
INNER JOIN SeqBranchTable t2
ON t2.SeqId = t1.SeqId
INNER JOIN Balancetable t3
ON t3.BalID = t2.BalID
GROUP BY t1.ClID) max_bal
ON t1.ClID = max_bal.ClID
AND t3.Balance = max_bal.bal
DEMO
But you should note this is not actually equivalent to using row_number (mouters solution). This may return multiple rows per ClID if there's a tie for max(balance). If you need that way of handling ties and you wanted to use a window function you could use RANK.
I want to achieve a full numeric scale from 0 to the max number in the table.
Let's say we have a table T with two fields named x and y
select x,y
from t
would show us lets say the results
X Y
3 11
5 23
7 45
9 1
10 34
I found this query to build sequential numbers:
With T_Misparim As
(Select 1 N
Union All
Select N+1 N
From T_Misparim
Where N<1000)
Select N
From T_Misparim
Option (MaxRecursion 0);
from this source : http://www.sqlserver.co.il/?p=3296
My bottom line is, how do i integrate the two queries into a single query to give
right outer join :
N X Y
0 null 0
1 null 0
2 null 0
3 3 11
4 null 0
5 5 23
6 null 0
7 7 45
8 null 0
9 9 1
10 10 34
You can just LEFT JOIN with the ordinal number CTE;
select 3 as X, 11 as Y into #TEST
insert #TEST values (5,23),(7,45),(9,1),(10,34)
;with NUMS(n) as (
select 0 union all
select 1 + n from NUMS where n < 50
)
select
NUMS.n N,
T.X,
isnull(T.Y, 0) Y
from NUMS
left join #TEST T on (T.X = NUMS.n)
option (maxrecursion 50)
For
N X Y
0 NULL 0
1 NULL 0
2 NULL 0
3 3 11
4 NULL 0
5 5 23
6 NULL 0
7 7 45
8 NULL 0
9 9 1
10 10 34