SQL SERVER 2008 final select command with stored procedure - database

i guess it is trivial to get it done right .
in the screen-shot below each user(userid) has two results (which is a kind of a duplicate)
how can i fix query to get only one result per user
(each user can have 2 sets of "TimeIn" and "TimeOut" activities)
so if given user does have a second "entrance" but did not leave yet
i need only the first closed entrance/leave + second entrance/still working
here is the Stored Procedure
create table #tmp (tId int, UserId int,
TimeIn1 smalldatetime, [TimeOut1] smalldatetime,
TimeIn2 smalldatetime, [TimeOut2] smalldatetime, tId2 int,
ActiveDate smalldatetime, ReasonID int, Name nvarchar(100), ReasonType nvarchar(100),
TotalMins int)
insert into #tmp (tId, UserId, TimeIn1, TimeOut1, ActiveDate, ReasonID, Name, ReasonType)
SELECT
t1.tId, t1.UserId, t1.TimeIn, t1.[TimeOut], t1.ActiveDate, t1.ReasonID, tblCustomers.name,tblTimeReas.ReasonType
FROM tblTime t1
inner join tblTimeReas on t1.ReasonID = tblTimeReas.ReasonID
inner join tblCustomers on t1.UserId=tblCustomers.custID
where (t1.userid in (select custID from tblCustomers where Classification =35) )
and (DATEPART(DAY,t1.timein)= DATEPART(DAY,GETDATE()))
and (DATEPART(MONTH,t1.timein)= DATEPART(MONTH,GETDATE()))
and (DATEPART(YEAR,t1.timein)= DATEPART(YEAR,GETDATE()))
update #tmp
set tId2 = (select top 1 tId from
tblTime t2 where (userid in (select custID from tblCustomers where Classification =35)) and DATEDIFF(day,t2.timein,#tmp.timein1)=0
and t2.tId>#tmp.tId order by tId asc)
update #tmp
set TimeIn2 = (select TimeIn from tblTime where tId=tId2),
TimeOut2 = (select [TimeOut] from tblTime where tId=tId2)
update #tmp set TotalMins = (
isnull(DATEDIFF(minute,timein1,timeout1),0)+
isnull(DATEDIFF(minute,timein2,timeout2),0)
)
select * from #tmp order by TimeIn1
drop table #tmp

dont know how , i didn't take a course for sql server & databse but this is my final code for
much flexable filtering
create table #tmp (tId int, UserId int,
TimeIn1 smalldatetime, [TimeOut1] smalldatetime,
ActiveDate smalldatetime, ReasonID int, Name nvarchar(100), ReasonType nvarchar(100),
TotalMins int)
insert into #tmp (tId, UserId, TimeIn1, TimeOut1, ActiveDate, ReasonID, Name, ReasonType)
SELECT
t1.tId, t1.UserId, t1.TimeIn, t1.[TimeOut], t1.ActiveDate, t1.ReasonID, tblCustomers.name,tblTimeReas.ReasonType
FROM tblTime t1
inner join tblTimeReas on t1.ReasonID = tblTimeReas.ReasonID
inner join tblCustomers on t1.UserId=tblCustomers.custID
where (t1.userid in (select custID from tblCustomers where Classification Like '%,35%') )
and (DATEPART(DAY,t1.timein)= DATEPART(DAY,GETDATE()))
and (DATEPART(MONTH,t1.timein)= DATEPART(MONTH,GETDATE()))
and (DATEPART(YEAR,t1.timein)= DATEPART(YEAR,GETDATE()))
and TimeOut is null
update #tmp set TotalMins = (
isnull(DATEDIFF(minute,timein1,GETDATE()),0)
)
select *from #tmp order by TimeIn1
drop table #tmp

Related

How to create another table or Temp table with the Pivot query results

I have this table
CREATE TABLE COMPUTERS
(
CUSTOMER_ID INT,
COMPUTER_NAME VARCHAR(50),
COMPUTER_OS VARCHAR(50)
);
INSERT INTO COMPUTERS
VALUES (15001, 'DESKTOP-JKVB','Windows 7'),
(15001, 'DESKTOP-SKVB','Windows 2012R2'),
(15002, 'PC-JKVB45','Windows VISTA'),
(15002, 'JOHN-PC','Windows 10'),
(15002, 'SERVER-DC','Windows 7'),
(15002, 'DATA-PC','Windows 2016'),
(15002, 'PC-BACKOFFICE','Windows 2008R2'),
(15003, 'DESKTOP-XPBACK','Windows 7'),
(15003, 'PC-HDFU','Windows 2012R2'),
(15003, 'DESKTOP-NO2','Windows 10'),
(15004, 'SERVER-DHCP','Windows 7'),
(15004, 'DESKTOP-NO1','Windows 2012R2');
With the help of Stack overflow , i have written a query to pivot the above data.
My question is whether we can create a temp table or normal table with result of the pivot data.
PIVOT QUERY
;WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Customer_ID ORDER BY Customer_ID) AS Number
FROM computers
),
cte2 AS
(
SELECT DISTINCT
c.Customer_ID,
c.Computer_Name,
'Computer_Name_' + CAST(Number AS VARCHAR(100)) AS Computer
FROM
cte AS c
),
cte_dist2 AS
(
SELECT DISTINCT Customer_ID
FROM computers
),
cte3 AS
(
SELECT
c.Customer_ID, c.Computer_OS,
'Computer_OS_' + CAST(Number AS VARCHAR(100)) AS OS
FROM
cte AS c
)
SELECT DISTINCT
cd2.Customer_ID,
MAX(IIF(c2.Computer='Computer_Name_1',c2.Computer_Name,NULL)) as Computer_Name_1,
MAX(IIF(c3.OS='Computer_OS_1',c3.Computer_OS,NULL)) as Computer_OS_1,
MAX(IIF(c2.Computer='Computer_Name_2',c2.Computer_Name,NULL)) as Computer_Name_2,
MAX(IIF(c3.OS='Computer_OS_2',c3.Computer_OS,NULL)) as Computer_OS_2,
MAX(IIF(c2.Computer='Computer_Name_3',c2.Computer_Name,NULL)) as Computer_Name_3,
MAX(IIF(c3.OS='Computer_OS_3',c3.Computer_OS,NULL)) as Computer_OS_3,
MAX(IIF(c2.Computer='Computer_Name_4',c2.Computer_Name,NULL)) as Computer_Name_4,
MAX(IIF(c3.OS='Computer_OS_4',c3.Computer_OS,NULL)) as Computer_OS_4,
MAX(IIF(c2.Computer='Computer_Name_5',c2.Computer_Name,NULL)) as Computer_Name_5,
MAX(IIF(c3.OS='Computer_OS_5',c3.Computer_OS,NULL)) as Computer_OS_5
FROM
cte_dist2 AS cd2
INNER JOIN
cte2 AS c2 ON cd2.Customer_ID = c2.Customer_ID
INNER JOIN
cte3 AS c3 ON cd2.Customer_ID = c3.Customer_ID
GROUP BY
cd2.Customer_ID
Yes you can use temp tables below show two methods that you can use for creating temp tables
select * into #temp from (--select query of the final cte function
or query) and temp table will be automatically create for you.
If you want to create your own temp table create temp table like below.
Eg
create table #Temp
(
EventID int,
EventTitle Varchar(50),
EventStartDate DateTime,
EventEndDate DatetIme,
EventEnumDays int,
EventStartTime Datetime,
EventEndTime DateTime,
EventRecurring Bit,
EventType int
)
and use Insert Into #Temp --select query of the final cte function
or query will also work for you.

Use INSERT within CASE statement in MSSQL

I'm using MSSQL. Below is my sql code
DECLARE #CoursesAboutToExpire TABLE (CourseID BIGINT, ExpiryDate DATE, IsApplicableToAllInternalUser BIT)
INSERT INTO #CoursesAboutToExpire
SELECT CourseID, ExpiryDate, IsApplicableToAllInternalUser
FROM CMS_CoursesMaster CM
DECLARE #ApplicableUsersWithCourse TABLE (UserID BIGINT, CourseID BIGINT)
SELECT 1 ,
(CASE WHEN CAE.IsApplicableToAllInternalUser = 1
THEN (INSERT INTO #ApplicableUsersWithCourse SELECT UM.UserID, CAE.CourseID FROM TRC_UserMaster UM)
ELSE (INSERT INTO #ApplicableUsersWithCourse SELECT CAP.UserID, CAP.CourseID FROM CMS_CourseApplicabilityParameters CAP WHERE CAP.CourseID=CAE.CourseID)
) AS 2
FROM #CoursesAboutToExpire CAE
I'm trying to insert records on the basis *IsApplicableToAllInternalUser * column value using case statement. but it gives error.
Now you can just replace the CASE statement you are trying to execute, with the following INSERT INTO .. SELECT statements:
DECLARE #ApplicableUsersWithCourse TABLE (UserID BIGINT, CourseID BIGINT)
INSERT INTO #ApplicableUsersWithCourse
SELECT UM.UserID, CAE.CourseID
FROM TRC_UserMaster UM JOIN #CoursesAboutToExpire CAE ON UM.CourseID = CAE.CourseID
WHERE CAE.IsApplicableToAllInternalUser = 1
INSERT INTO #ApplicableUsersWithCourse
SELECT CAP.UserID, CAP.CourseID
FROM CMS_CourseApplicabilityParameters CAP JOIN #CoursesAboutToExpire CAE ON CAP.CourseID=CAE.CourseID
WHERE CAE.IsApplicableToAllInternalUser = 0
You can initially test the records you are going to insert by just executing the SELECT statements first. If it looks OK, you can insert the records.
This can also be written as follows:
INSERT INTO #ApplicableUsersWithCourse
SELECT UM.UserID, CAE.CourseID
FROM TRC_UserMaster UM JOIN #CoursesAboutToExpire CAE ON UM.CourseID = CAE.CourseID
WHERE CAE.IsApplicableToAllInternalUser = 1
UNION ALL
SELECT CAP.UserID, CAP.CourseID
FROM CMS_CourseApplicabilityParameters CAP JOIN #CoursesAboutToExpire CAE ON CAP.CourseID=CAE.CourseID
WHERE CAE.IsApplicableToAllInternalUser = 0
Below code worked for me.
DECLARE #CoursesAboutToExpire TABLE (CourseID BIGINT, ExpiryDate DATE, IsApplicableToAllInternalUser BIT)
INSERT INTO #CoursesAboutToExpire
SELECT CourseID, ExpiryDate, IsApplicableToAllInternalUser FROM CMS_CoursesMaster CM
DECLARE #ApplicableUsersWithCourse TABLE (UserID BIGINT, CourseID BIGINT)
INSERT INTO #ApplicableUsersWithCourse
SELECT UM.UserID, CAE.CourseID FROM TRC_UserMaster UM
CROSS JOIN #CoursesAboutToExpire CAE
WHERE CAE.IsApplicableToAllInternalUser = 1)
INSERT INTO #ApplicableUsersWithCourse
SELECT CAP.UserID, CAP.CourseID FROM CMS_CourseApplicabilityParameters CAP
INNER JOIN #CoursesAboutToExpire CAE ON CAP.CourseID=CAE.CourseID
WHERE CAE.IsApplicableToAllInternalUser = 0

SQL:How to keep inserting record number in the target table in INSERT INTO statement

I have query like this:
declare #guidd nvarchar(10)
set #guidd = '11233'
create table rrr_temp(value nvarchar(10), value2 int)
create table rrr_tempA(valueA nvarchar(10), guidd nvarchar(10), ranks int)
insert into rrr_temp values('AAA', 200)
insert into rrr_temp values ('BBB', 400)
insert into rrr_temp values ('CCC', 300)
INSERT INTO rrr_tempA(valueA , guidd , ranks )
SELECT RT.value, #guidd , row_number() over (order by (select NULL))
FROM rrr_temp(nolock) RT
INNER JOIN
(SELECT value, min(value2) AS lastLeg
FROM rrr_temp(nolock) RTL
GROUP BY value) GrpRoute
ON RT.value = GrpRoute.value
ORDER BY value2
select * from rrr_tempA
With the above INSERT iNTO statement, i am able to insert only the record number of source table(rrr_temp) for 'ranks' column of Target table by using 'row_number() over (order by (select NULL))'. But, i want the number to be incremented when target table got inserted. i cannot use IDENTITY. Thanks.
Are you asking about something like this?
select #max_rank = max(ranks)
from rrr_tempA
set #max_rank = IsNull(#max_rank, 0)
INSERT INTO rrr_tempA(valueA , guidd , ranks )
SELECT RT.value, #guidd , #max_rank + row_number() over (order by (select NULL))

Leave Approval Status in SQL Server

I am using SQL Server 2008 R2, I want to display leave application status that can be either apply, approve, reject or cancel.
If all leave approve then status = approve, like other leaves
but if there are mix status e.g some leave approve , some rejected then status = Partial.
I have written the code but I feel it is complicated, can I get it in one, single query?
create table #t
(
employeeID int,
LeaveCode nvarchar(10),
status nvarchar(50)
)
insert into #t
values(1, 'PL', 'Approve'), (1, 'PL', 'Reject'), (1, 'PL', 'Approve')
;with ct1 as
(
select status, count(status) Cnt
from #t
group by status
),
counters as
(
select count(*) as TotalLeave
from #t
)
select top(1)
CASE
WHEN C1.Cnt = C2.TotalLeave
THEN C1.status
ELSE 'Partial'
END [status]
from
ct1 C1
cross join
counters C2
drop table #t
try this,
create table #t
(
employeeID int,
LeaveCode nvarchar(10),
status nvarchar(50)
)
insert into #t values(1,'PL','Approve'),(1,'PL','Reject'),(1,'PL','Approve')
insert into #t values(2,'PL','Approve'),(2,'PL','Approve'),(2,'PL','Approve')
SELECT
employeeID,
CASE WHEN count(DISTINCT status) = 1 THEN MAX(status) ELSE 'Partail' END [status]
FROM #t
GROUP BY employeeID
drop table #t
SELECT
CASE
WHEN COUNT(DISTINCT t.status) > 1 THEN 'Partial'
ELSE MAX(t.status)
END OveralLeaveStatus
FROM #t t
simply group by employee and check for max(status) <> min(status), if it is difference than it means at least one the status is different
select employeeID,
[status] = case when min([status]) <> max([status]) then 'Partial'
else min([status])
end
from #t
group by employeeID

T-SQL Update From Order By

I am trying to write a Stored Procedure that will give me Audit information between a date range. The Audit table stores the Audit Date, Column Name and Old Value. I want to display the Old Value and the New Value in the result set. I need to get the new value from the next most recent Audit entry or from the entity itself. The stored procedure is a multi step approach to get the result set I need.
Create a #results temp table with the Audit records from within the date range.
Create a #currentValues temp table with the current values from the entity.
Update the #results table to store the new value
Here is the structure of the Audit Table:
AuditId uniqueidentifier NEWID()
AuditDate datetime GETDATE()
UserId uniqueidentifier
EntityId uniqueidentifier
ColumnName nvarchar(100)
OldValue nvarchar(MAX)
Here is the sql:
CREATE PROC GetAuditSummary
#StartDate datetime = NULL,
#EndDate datetime = NULL
AS
DECLARE #Results table(
AuditId uniqueidentifier,
AuditDate datetime,
UserId uniqueidentifier,
EndityId uniqueidentifier,
ColumnName nvarchar(100),
OldValue nvarchar(MAX),
NewValue nvarchar(MAX)
INSERT INTO #Results(AuditId, AuditDate, UserId, EntityId, ColumnName, OldValue)
SELECT AuditId, AuditDate, UserId, EntityId, ColumnName, OldValue
FROM Audit
WHERE (AuditDate >= #StartDate) AND (AuditDate < #EndDate)
DECLARE #CurrentValues table(
EntityId uniqueidentifier,
ColumnName nvarchar(100),
Value nvarchar(MAX)
)
--Lengthy Code to fill #CurrentValues temp table. Assume #CurrentValues is populated
UPDATE #Results
SET NewValue = n.Value
FROM #Results r INNER JOIN
(SELECT AUditId, AuditDate, EntityId, ColumnName, OldValue AS Value
FROM Audit
UNION ALL
SELECT NULL, GETDATE(), EntityId, ColumnName, Value
FROM #CurrentValues
ORDER BY AuditDate DESC
) n ON n.EntityId = r.EntityId AND
n.ColumnNmae = r.ColumName NAD
n.AuditDate > r.AuditDate
SELECT * FROM #Results ORDER BY AuditDate DESC
Now, and correct me if I'm wrong, when the update statement executes, the NewValue should be set to the last matching row in the joined result set and since I have the subquery ordered by AuditDate, the AuditDate closest to the current record from #Results should be the value that's set to NewValue. I've tried this, but I get an error telling me I can't use an Order By in a subquery. Is there another way to do this? I'm open to any suggestions, but I need to take performance into consideration as there is a chance of having thousands of rows in the result.
--EDIT
Here is one way to get it working, but I'm not sure it's the best on performance.
UPDATE #Results
SET NewValue = COALESCE(
(SELECT TOP 1 a.OldValue
FROM Audit a
WHERE (a.EntityId = r.EntityId) AND
(a.ColumnName = r.ColumnName) AND
(a.AuditDate > r.AuditDate)
ORDER BY a.AuditDate),
(SELECT TOP 1 c.Value
FROM #CurrentValues c
WHERE (c.EntityId = r.EntityId) AND
(c.ColumnName = r.ColumnName))
FROM #Results r
I would use Row_Number or Rank function to get the row after last matching row.
Following example should work, you may want to change (order by n.AuditDate) to (order by n.AuditDate desc) if you want most recent record after matching date.
UPDATE #Results
SET NewValue = n.Value
FROM #Results r
INNER JOIN
(
select n.EntityId, n.ColumnName, n.Value, Row_Number() over(partition by n.EntityId, n.ColumnName order by n.AuditDate) RowNumber
from
#Results ir
inner join (
SELECT AuditDate, EntityId, ColumnName, OldValue AS Value
FROM Audit
UNION ALL
SELECT GETDATE(), EntityId, ColumnName, Value
FROM #CurrentValues
) inn on inn.EntityId = ir.EntityId AND
inn.ColumnNmae = ir.ColumName NAD
inn.AuditDate > ir.AuditDate
) n ON n.EntityId = r.EntityId AND
n.ColumnNmae = r.ColumName AND
n.RowNumber = 1

Resources