I have two tables. One is employee attendance and second one is Employee Leave.
Employee attendance col( Empid,INTIME,OUTTIME,Status)
Employee Leave col(Empid,StartDate,Endate,leavetype(PL,CL,SL))
I have created pivot table in which present, absent and HD mentioned and created another separate query for sum of row (Present ,absent and HD) From EmployeeAttendance Table.
===Sum query===
SELECT SUM(CASE WHEN status = 'P' THEN 1
WHEN status = 'HD' THEN 0.5 WHEN status = 'A' THEN 0 END) AS [T.P],
SUM(CASE WHEN status = 'A' THEN 1 WHEN status = 'HD' THEN 0.5 END) AS [A],
SUM(CASE WHEN status = 'P' THEN 1
WHEN status = 'HD' THEN 1 WHEN status = 'A' THEN 1 END) AS [TDay ]
FROM EmployeesAttendance
--WHERE (ReportingDate BETWEEN #StartDate AND #Enddate)
GROUP BY EmpID
===Pivot Table ===
for converting col into row
SELECT DISTINCT ReportingDate INTO #Dates
FROM EmployeesAttendance
ORDER BY ReportingDate
DECLARE #cols NVARCHAR(4000)
SELECT #cols = COALESCE(#cols + ',[' + CONVERT(varchar, DATEPART(DAY, ReportingDate), 112)
+ ']','[' + CONVERT(varchar,DATEPART(DAY, ReportingDate), 112) + ']')
FROM #Dates
ORDER BY ReportingDate
DECLARE #qry NVARCHAR(4000) =
N'SELECT *
FROM (SElECT EmployeeDetails.EmpID,EmployeeDetails.EmpName,EmployeesAttendance.Status,
DATEPART(DAY, EmployeesAttendance.ReportingDate)as DDate
FROM EmployeesAttendance Inner Join EmployeeDetails on EmployeesAttendance.EmpID=EmployeeDetails.Empid )
emp
PIVOT (MAX(Status) FOR DDate IN (' + #cols + ')) AS stat
-- Executing the query
EXEC(#qry)
I want this Employee attendance Register.
Date 1 2 3 4 5 Total Absent Present Leave
Emp1 P P A PL P 5 1 3 1
Emp2 Cl pl A PL P 5 1 2 2
Now I want to merge above bother query of Sum and Pivot, also mentioned leave type in attendance register if employee availed leaves From 01-01-2019 to 02-01-2019 Noofdays equal to 2 for (emp2)
I have the below string:
Consolidation CompletedThe Scenario is LDP; the Year is 2018; the Start Period is July; the End Period is June; the Entity is TOT_NEWS.
And need to get the words just before the semicolon (;) and the last word before the dot (.)
Result:
----- ---- ---- ---- ----
LDP 2018 July June TOT_NEWS
I could obtain the first one LDP with the below select:
REVERSE(LEFT(REVERSE(SUBSTRING(strDescription, CHARINDEX('The Scenario
is', strDescription,+39),
CHARINDEX(';',strDescription,-1))), CHARINDEX (' ',
REVERSE(SUBSTRING(strDescription,
CHARINDEX('The Scenario is', strDescription,+39),
CHARINDEX(';',strDescription,-1)))))) as Scenario
But it doesn´t work for the rest of the string.
Here's a way using a string splitter...
declare #value varchar(max) = 'Consolidation CompletedThe Scenario is LDP; the Year is 2018; the Start Period is July; the End Period is June; the Entity is TOT_NEWS.'
;with cte as(
select
* from
dbo.DelimitedSplit8K(#value,';'))
select
replace(right(Item,charindex(' ',reverse(Item),1)),'.','')
from cte
THE FUNCTION
CREATE FUNCTION [dbo].[DelimitedSplit8K] (#pString VARCHAR(8000), #pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
enough to cover VARCHAR(8000)*/
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(#pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(#pString,t.N,1) = #pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(#pDelimiter,#pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(#pString, l.N1, l.L1)
FROM cteLen l
;
GO
Creator of the Function
If you are open to a TVF (Table-Valued Function).
This approach uses a modifed split/parse function. Rather than one delimeter, I use two non-like delimiters. It this case a ' ' and ';'
Example
Declare #YourTable table (id int,strDescription varchar(max))
Insert Into #YourTable values
(1,'Consolidation CompletedThe Scenario is LDP; the Year is 2018; the Start Period is July; the End Period is June; the Entity is TOT_NEWS.')
Select A.ID
,B.*
From #YourTable A
Cross Apply (
Select Pos1 = max(case when RetSeq=1 then RetVal end)
,Pos2 = max(case when RetSeq=2 then RetVal end)
,Pos3 = max(case when RetSeq=3 then RetVal end)
,Pos4 = max(case when RetSeq=4 then RetVal end)
,Pos5 = max(case when RetSeq=5 then RetVal end)
From [dbo].[udf-Str-Extract](A.strDescription+';',' ',';')
) B
Returns
ID Pos1 Pos2 Pos3 Pos4 Pos5
1 LDP 2018 July June TOT_NEWS
The UDF if Interested
CREATE FUNCTION [dbo].[udf-Str-Extract] (#String varchar(max),#Delimiter1 varchar(100),#Delimiter2 varchar(100))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter1) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter1)) = #Delimiter1),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter1,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By N)
,RetPos = N
,RetVal = left(RetVal,charindex(#Delimiter2,RetVal)-1)
From (
Select *,RetVal = Substring(#String, N, L)
From cte4
) A
Where charindex(#Delimiter2,RetVal)>1
)
/*
Max Length of String 1MM characters
Declare #String varchar(max) = 'Dear [[FirstName]] [[LastName]], ...'
Select * From [dbo].[udf-Str-Extract] (#String,'[[',']]')
*/
Here you go:
-- Defining your string
DECLARE #string varchar(max)
SET #string = 'Consolidation CompletedThe Scenario is LDP; the Year is 2018; the Start Period is July; the End Period is June; the Entity is TOT_NEWS.'
;with pos as (
SELECT
#string as String
,CHARINDEX(';', #string, 1) as Pos_1
,CHARINDEX(';', #string, CHARINDEX(';', #string, 1)+1) as Pos_2
,CHARINDEX(';', #string, CHARINDEX(';', #string, CHARINDEX(';', #string, 1)+1)+1) as Pos_3
,CHARINDEX(';', #string, CHARINDEX(';', #string, CHARINDEX(';', #string, CHARINDEX(';', #string, 1)+1)+1)+1) as Pos_4
) , txt as (
select
String
,substring(String, 1,Pos_1-1) as String_1
,substring(String,Pos_1+1,Pos_2-Pos_1-1) as String_2
,substring(String,Pos_2+1,Pos_3-Pos_2-1) as String_3
,substring(String,Pos_3+1,Pos_4-Pos_3-1) as String_4
,substring(String,Pos_4+1,LEN(String)-Pos_4-1) as String_5
from pos
)
SELECT
string
,substring(String_1,len(String_1)-charindex(' ',reverse(String_1),1)+1,charindex(' ',reverse(String_1))) as Result_1
,substring(String_2,len(String_2)-charindex(' ',reverse(String_2),1)+1,charindex(' ',reverse(String_2))) as Result_2
,substring(String_3,len(String_3)-charindex(' ',reverse(String_3),1)+1,charindex(' ',reverse(String_3))) as Result_3
,substring(String_4,len(String_4)-charindex(' ',reverse(String_4),1)+1,charindex(' ',reverse(String_4))) as Result_4
,substring(String_5,len(String_5)-charindex(' ',reverse(String_5),1)+1,charindex(' ',reverse(String_5))) as Result_5
from txt
Output:
string | Result_1 | Result_2 | Result_3 | Result_4 | Result_5
----------------------------------------------------------------------------------------------------------------------------------------|-----------|----------|----------|----------|---------
Consolidation CompletedThe Scenario is LDP; the Year is 2018; the Start Period is July; the End Period is June; the Entity is TOT_NEWS. | LDP | 2018 | July | June | TOT_NEWS
How could I put those multiple rows into one line, and the contents are in different columns:
From:
ID | Subject1/Catalog/Session
10868952 | NUR/3110/D507
10868952 | NUR/3110/D512
10868952 | NUR/4010/D523
10868952 | NUR/4010/HD20
To
ID |Subject1/Catalog/Session |Subject2/Catalog/Session | Subject3/Catalog/Session |Subject4/Catalog/Session | Subject5/Catalog/Session
10868952 |NUR/3110/D507 | NUR/3110/D512 | NUR/4010/D523 | NUR/4010/HD20 |
Would be best if in the future you can provide ddl and sample data. I did this for you this time.
Here is how you could do this if you know the number of elements per row. I put links in the comments of the original post to both the static and dynamic versions of this type of approach.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
ID int,
Subject1 varchar(50)
)
insert #Something
select 10868952, 'NUR/3110/D507' union all
select 10868952, 'NUR/3110/D512' union all
select 10868952, 'NUR/4010/D523' union all
select 10868952, 'NUR/4010/HD20';
with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from #Something
)
select ID
, MAX(Case when RowNum = 1 then Subject1 end) as Subject1
, MAX(Case when RowNum = 2 then Subject1 end) as Subject2
, MAX(Case when RowNum = 3 then Subject1 end) as Subject3
, MAX(Case when RowNum = 4 then Subject1 end) as Subject4
from OrderedResults
group by ID
Here is how you can do this as a dynamic pivot. There are a number of concepts going on here. One is a tally table. In this code it is implemented as a cte. In my actual system I have this as a view. It generates 10,000 rows with zero reads. The tally table and most of the other concepts here were learned by the immortal Jeff Moden. If you do not know what a tally table is or how they work, check out Jeff's article here. http://www.sqlservercentral.com/articles/T-SQL/62867/
I will post some code for how to do this for this example but anybody who is unfamiliar with this technique should read his article. http://www.sqlservercentral.com/articles/Crosstab/65048/
Here is a full working example of doing this as a dynamic cross tab. When you are satisfied that the sql this generates is safe feel free to uncomment the last two lines.
LAST but certainly not least. Make sure that you fully understand what this code and how it works. It is not going to be my phone that rings at 3am when something goes wrong. You are the one who will have to be there to support this code.
if OBJECT_ID('Something') is not null
drop table Something
create table Something
(
ID int,
Subject1 varchar(50)
)
insert Something
select 10868952, 'NUR/3110/D507' union all
select 10868952, 'NUR/3110/D512' union all
select 10868952, 'NUR/4010/D523' union all
select 10868952, 'NUR/4010/HD20' union all
select 12345, 'asdfasdf'
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from Something
)
select ID';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Subject1 end) as Subject' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from Something
group by ID
order by COUNT(*) desc
)
select #StaticPortion + #DynamicPortion + #FinalStaticPortion
--declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
--exec sp_executesql #SqlToExecute
I am trying to select 5 records in each ItemCategoryID with paging, with the query below I am able to get 5 records in each category but paging is not working, as i have declared page size 10, but i am getting 19 records and #ItemCounter TotalCount is coming as 45... i m not getting how to solve it..here is the query:
DECLARE #PageIndex int = 1
DECLARE #PageSize int = 10
DECLARE #StartRow int
DECLARE #EndRow int
SET #StartRow = (#PageSize * (#PageIndex - 1)) + 1
SET #EndRow = #PageSize * #PageIndex + 1
DECLARE #ItemCounter int
SELECT #ItemCounter = Count(*)FROM dbo.Auctions WHERE AuctionStatus=1;
WITH Auctions AS
(
SELECT ROW_NUMBER() OVER
(PARTITION BY ItemCategoryID ORDER BY AuctionID) AS RowNumber,
AuctionID,
ItemCategoryID ,
#ItemCounter TotalCount
FROM Auctions
WHERE
AuctionStatus=1
)
SELECT a.* FROM Auctions a
WHERE a.RowNumber <=3 AND a.RowNumber
BETWEEN #StartRow AND #EndRow - 1
Thanks in advance.
a.RowNumber <=3 AND a.RowNumber BETWEEN #StartRow AND #EndRow - 1
What exactly do you expect from this? the row number has to be between start and end AND it has to be less than or equal to 3? What is start is 4? Any End above 3 is irrelevant.
I'm going to make a leap of faith here and say that the correctly stated requirement for your problem is:
for each item category, return at most 4 auctions where status = 1
page the result
so you obviously have two counters to consider, one for auctions within category and one for paging:
WITH Auctions AS
(
SELECT ROW_NUMBER() OVER
(PARTITION BY ItemCategoryID ORDER BY AuctionID) AS AuctionNumber,
AuctionID,
ItemCategoryID
FROM Auctions
WHERE
AuctionStatus=1
),
Paging as (
SELECT ROW_NUMBER() OVER (ORDER BY ItemCategoryID, AuctionID) as RowNumber
, a.*
FROM Auctions a
WHERE AuctionNumber <= 3
)
SELECT *
FROM Paging
WHERE RowNumber BETWEEN #StartRow AND #EndRow - 1;
Performance will be likely bad, but nobody can design any performance w/o data schema knowledge (table definition, indexes etc) which are missing from the problem statement.
TotalRecordCount:
WITH Auctions AS
(
SELECT ROW_NUMBER() OVER
(PARTITION BY ItemCategoryID ORDER BY AuctionID) AS AuctionNumber,
AuctionID,
ItemCategoryID ,
FROM Auctions
WHERE AuctionStatus=1
)
SELECT #total = COUNT(*)
FROM Auctions a
WHERE AuctionNumber <= 3;
I am talking about SQL Server 2008. I have table with three nvarchar columns. I want to select first column at Nth row, second column from Mth row, third column from Kth row where M,N,K are not equal one to another.
How to write such a query? Also is it possible to select random row?
You can use a CTE with a ROW_NUMBER() function to achieve this:
;WITH CTE AS
(
SELECT
Column1, Column2, Column3,
(your list of additional columns - if needed),
RN = ROW_NUMBER() OVER (ORDER BY InsertionDate)
)
SELECT
FirstValue = (SELECT Column1 FROM CTE WHERE RN = N),
SecondValue = (SELECT Column2 FROM CTE WHERE RN = M),
ThirdValue = (SELECT Column3 FROM CTE WHERE RN = K)
You need to replace the N, M, K with actual integer values in this query - or define SQL variables to hold those three values.
declare #i1 int;
declare #i2 int;
declare #i3 int;
SET #i1=2;
SET #i2=4;
SET #i3=1;
;with t1 as
(
select *,row_number() over(order by (select 0)) as rn from t
)
select max(CASE rn WHEN #i1 then N1 else '' end),
max(CASE rn WHEN #i2 then N2 else '' end),
max(CASE rn WHEN #i3 then N3 else '' end)
from t1 where rn in (#i1,#i2,#i3);