How to run SQL Server CTE more than once? - sql

I am running a CTE Query as given below
WITH CTE AS(
SELECT EmpId, EmpName, RN = ROW_NUMBER()OVER(PARTITION BY EmpId ORDER BY EmpId)
FROM Employeetemp
)
SELECT * FROM CTE
DELETE FROM CTE WHERE RN > 1
But I am getting issues in it as I can run either Select Query or Delete Query.
My second question is "What is CTE" ? Is it an object, view or anything else.
Thanks a lot in advance.

You cannot do this in SQL Server with a single query. Instead, one method to do what you want uses a temporary table:
SELECT EmpId, EmpName,
RN = ROW_NUMBER()OVER(PARTITION BY EmpId ORDER BY EmpId)
INTO #EmployeeTemp
FROM Employeetemp;
SELECT * FROM Employeetemp;
DELETE FROM Employeetemp
WHERE EmpId IN (SELECT EmpId FROM #Employeetemp WHERE RN > 1);

Related

Perform pivot operation on the table but facing problem as it requires multiple aggregate function to segregate dates into two columns

I have this table named hotel which contains EmpId and their corresponding [check-in/out] column in datetime format.
Now, I want the data in table to look like this.
I have tried following simple query and it's working correctly:
select EmpId, min([Check-in/out]) as Checkin, max([Check-in/out]) as Checkout
from [dbo].[hotel]
group by EmpId;
But i want to do it using pivot operator in sql server. I have tried the following query but it's incorrect:
select EmpId, Min([Check-in/out]) AS Checkin, Max([Check-in/out]) AS Checkout
FROM
(select EmpId, [Check-in/out] from [dbo].[hotel]) AS SourceTable
PIVOT
(
min([Check-in/out])
FOR [Check-in/out] IN(Checkin)
)AS PivotTable1
PIVOT
(
max([Check-in/out])
FOR [Check-in/out] IN(Checkout)
)AS PivotTable2;
Here again my comment as answer with an example:
I suggest using cte / subqueries in order to approach this problem... first of all, select EmpID, time and rownumber (partition by empid and order by time) - this gives you all checkins with odd rownumber and all checkouts with even rownumber. Next - basing on this query - select empid, time and CASE WHEN rownumber%2=0 THEN 'CHECKOUT' ELSE 'CHECKIN' END AS CheckInOut... this result again can be used in your pivot statement
Example:
WITH cte AS(
SELECT *, ROW_NUMBER() OVER (PARTITION BY EmpID ORDER BY CheckInOut) rn
FROM T1
),
cteInOut AS(
SELECT EmpID, CheckInOut, CASE WHEN rn%2 = 0 THEN N'CheckOut' ELSE N'CheckIn' END AS CheckInOutState
FROM cte
),
cteInOuntSrt AS(
SELECT EmpID, CheckInOut, CheckInOutState, ROW_NUMBER() OVER (PARTITION BY EmpID, CheckInOutState ORDER BY CheckInOut) rn1
FROM cteInOut
)
select EmpID, rn1 AS CheckIndIdx, CheckIn, CheckOut
from cteInOuntSrt
pivot
(
min(CheckInOut)
for CheckInOutState in ([CheckIn], [CheckOut])
) piv
ORDER BY 1, 2;
fiddle: http://sqlfiddle.com/#!18/af6f3/1/1
If the values line up, you can use lead() and row_number():
select c.empid, checkin, checkout
from (select c.*, [Check-in/out] as checkin,
lead([Check-in/out]) over (partition by empid order by [Check-in/out]) as checkout,
row_number() over (partition by empid order by [Check-in/out]) as seqnum
from [Check-in/out] c
) c
where seqnum % 2 = 1;
This does the following calculations:
Calculate the next date/time value.
Enumerate the rows, starting the count from 1.
Taking the odd-numbered rows. These are the check ins.

How to convert this query to SQL Server 2000 syntax

I am running this query to SQL Server 2008+ but it doesn't work on SQL Server 2000.
and i need this to execute.
WITH CTE AS (
SELECT
custnum,
custname,
RN = ROW_NUMBER() OVER( PARTITION BY custnum, custname ORDER BY custnum )
FROM
cust
)
SELECT
*
FROM
CTE
WHERE RN > 1
thank you so much for your help!
Prior to SQL Server 2005, this problem domain was solved with ordered inserts into a #temp table with an IDENTITY column to generate the sequence number. This would solve RANK() and ROW_NUMBER() requirements.
E.g.:
-- Create empty temp table
SELECT custnum, custname, IDENTITY(INT, 1, 1) as RN
INTO #cust
FROM cust
WHERE 0 = 1
-- Populate with ORDER BY, to generate ascending RN
INSERT INTO #cust
(custnum, custname)
SELECT
custnum, custname
FROM
cust
ORDER BY
custnum, custname
At that point, you can query MIN() for each custnum/custname grouping and use that as you'd use the CTE.
However ... is ROW_NUMBER() really what you want here ? Seems like you'd want RANK(), not ROW_NUMBER().
See if this works
select custnum,custname from
(
select (select count(*) from cust as t1 where t1.custnum<=t2.custnum) as sno,
custnum,custname from cust as t2
) as t
where sno>1

How to use distinct when you select multiple column in SQL

I have use simple inner join statement and getting result into CTE table. I want to select distinct 'ServiceId' from CTE. I have following query
SELECT DISTINCT(ServicesId), ServiceNo, ServiceDate, DealerCode FROM CTE_Temp
Suppose there are duplicate entries of ServiceId in CTE then I want to select first entry only and ignore rest of them.
You can use ROW_NUMBER() OVER() for this. Just replace the column in the ORDER BY to define what's first.
;WITH AnotherCTE AS(
SELECT
ServicesId, ServiceNo, ServiceDate, DealerCode,
RN = ROW_NUMBER() OVER(PARTITION BY ServicesID ORDER BY ServiceDate DESC)
FROM CTE_Temp
)
SELECT
ServicesId, ServiceNo, ServiceDate, DealerCode
FROM AnotherCTE
WHERE RN = 1

Performance tuning of this query?

I have below query to support employee pagination sorted by employee name
SELECT rowNumAlias
,Employee.employeeId
,Employee.NAME
FROM (
SELECT row_number() OVER (
ORDER BY Employee.NAME ASC
) rowNumAlias
,employeeId
,NAME
FROM Employee
) employeeData
INNER JOIN Employee ON Employee.employeeId = employeeData.employeeId
WHERE rowNumAlias BETWEEN ? AND ?
Where parameter rowNumAlias can be any integer number between 1 and 100
This query is taking around 7 seconds on my sql server database having 1 million records. Is there a way i can minimize query execution time ?
You can try like this:
SELECT * FROM (
SELECT (SELECT row_number() OVER (ORDER BY e2.NAME ASC) FROM Employee e2 WHERE Employee.employeeId = E2.employeeId) rowNumAlias,
,Employee.employeeId
,Employee.NAME
FROM Employee
) e3 WHERE e3.rowNumAlias BETWEEN ? AND ?
You can try to use CTE for this.
;WITH employeeData as
(
SELECT row_number() OVER (ORDER BY Employee.NAME ASC) rowNumAlias,
employeeId,
NAME
FROM Employee
)
SELECT employeeData.rowNumAlias,
employeeData.employeeId,
employeeData.NAME
FROM employeeData
INNER JOIN Employee ON Employee.employeeId = employeeData.employeeId
WHERE rowNumAlias BETWEEN ? AND ?
If you are on SQL Server 2012+ you can use the ORDER BY ... OFFSET ... FETCH ...syntax to do pagination:
SELECT EmployeeId, Name
FROM Employee
ORDER BY Employee.Name ASC OFFSET ? ROWS FETCH NEXT ? ROWS ONLY
OFFSET specifies how many rows to skip and FETCH NEXT how many to get. See the documentation.
In earlier versions you should be able to get better performance by using a common table expression (with proper indexes this query looks like it executes in halt the time of your original according to my execution plan):
;With cte (rownum, employeeid, name) as (
SELECT
rownum = row_number() OVER (ORDER BY employee.name ASC),
employeeid,
name
FROM employee
)
SELECT rownum, employeeid, name
FROM cte
WHERE rownum BETWEEN ? AND ?;

Select the first instance of a record

I have a table, myTable that has two fields in it ID and patientID. The same patientID can be in the table more than once with a different ID. How can I make sure that I get only ONE instance of every patientID.?
EDIT: I know this isn't perfect design, but I need to get some info out of the database and today and then fix it later.
You could use a CTE with ROW_NUMBER function:
WITH CTE AS(
SELECT myTable.*
, RN = ROW_NUMBER()OVER(PARTITION BY patientID ORDER BY ID)
FROM myTable
)
SELECT * FROM CTE
WHERE RN = 1
It sounds like you're looking for DISTINCT:
SELECT DISTINCT patientID FROM myTable
you can get the same "effect" with GROUP BY:
SELECT patientID FROM myTable GROUP BY patientID
The simple way would be to add LIMIT 1 to the end of your query. This will ensure only a single row is returned in the result set.
WITH CTE AS
(
SELECT tableName.*,ROW_NUMBER() OVER(PARTITION BY patientID ORDER BY patientID) As 'Position' FROM tableName
)
SELECT * FROM CTE
WHERE
Position = 1