SQL Query related to maximum job period - sql

I am having a table with four columns namely, eid,ename,hire_date and end_date. Now I want to write a query displaying the name and id of the employee who has worked for the maximum days and the no. of days for which he/she has worked. I have tried a lot but unfortunately I am not getting the desired answer.

Hth..
CREATE TABLE tests
(eid int,ename VARCHAR(20),hire_date DATETIME , end_date Datetime)
INSERT INTO dbo.tests
( eid ,
ename ,
hire_date ,
end_date
)
VALUES ( 1 , -- eid - int
'A1' , -- ename - varchar(20)
'2015-01-03 10:41:43' , -- hire_date - datetime
'2015-03-03 10:41:43' -- end_date - datetime
),
( 2 , -- eid - int
'A2' , -- ename - varchar(20)
'2015-05-03 10:41:43' , -- hire_date - datetime
'2015-06-03 10:41:43' -- end_date - datetime
)
SELECT TOP 1 eid,ename,DATEDIFF(DAY,hire_date,end_date) AS DaysWORKED FROM tests ORDER BY DATEDIFF(DAY,hire_date,end_date) desc
Thanks

Related

Need to Impute Missing Data from Sparsely Populated Table

I am trying to populate a #temp reporting table from an existing sparse table with 2 key elements-- datekeys and prices based on a date range and prices as they change. Here is the data that exists in the price change table:
The date range for a report 2 days ago on a rolling 7 day cycle would include 6/12 - 6/19. The 2 rows in the table have an old price and old price variance from 6/7 out of range for that report, however, the price and variance is needed in order to dub it in under the CashPrice column for all datekeys 20190612 through 20190618. On 6/19 there is a new price change/variance. On that
datekey, the new price/variance values should change.
The set-up data required for reporting would like this:
Here is the code to build the sampling data:
-- T-SQL script to build the sampling tables
-- use for date-related cross-join later
if object_id( N'tempdb..#Numbers', N'U' ) is not null
drop table #Numbers;
create table #Numbers(
n int
);
insert #Numbers( n ) values( 0 ), ( 1 ), ( 2 ), ( 3 ), ( 4 ), ( 5 ), ( 6 ),
( 7 ), ( 8 ), ( 9 ), ( 10 )
-- select * from #Numbers;
-- creating existing sparse price data
if object_id( N'tempdb..#dt', N'U' ) is not null
drop table #dt;
create table #dt(
StoreNumber int
, City char( 3 )
, State char( 2 )
, Type char( 1 )
, ProductKey int
, DateKey int
, CashPrice money
, DateLastPriceChange datetime
, CashPriceVar money
)
insert #dt values
( 1, 'OKC', 'OK', 'D', 144, 20190607, 2.799, '2019-06-07 11:37', -0.1 )
, ( 1, 'OKC', 'OK', 'D', 144, 20190619, 2.699, '2019-06-19 10:40', -0.1 )
-- select * from #dt;
-- creaing temporary working table for reporting
if object_id( N'tempdb..#tt', N'U' ) is not null
drop table #tt;
create table #tt(
StoreNumber int
, City char( 3 )
, State char( 2 )
, Type char( 1 )
, ProductKey int
, DateKey int
-- a couple of extra columns here
, DateKeyDate date
, DataDateKey int
, CashPrice money
, DateLastPriceChange datetime
, CashPriceVar money
)
-- dub in the start date for the report
declare #StartDateKey date = '2019-06-12'
-- populate the temporary working table
insert #tt( StoreNumber, ProductKey, DateKeyDate )
select distinct
dt.StoreNumber
, dt.ProductKey
, dateadd( day, n.n, #StartDateKey )
from #dt dt
cross join #Numbers n
where
n.n <= 7
-- select * from #tt
-- change the added datekeydate to datekey format
update #tt
set DateKey = year( DateKeyDate ) * 10000 + month( DateKeyDate ) * 100 +
day( DateKeyDate )
Here is the code that I have been working on that limps along. It's not ideal and in many cases against the full suite of data, it filters out the dates I cross-joined, so that I am left without the imputed data-- showing only the original known price changes. Please advise.
select
dd.StoreNumber
, dto.City
, dto.State
, dto.Type
, dd.ProductKey
, dd.DateKey
, dto.CashPrice
, dto.DateLastPriceChange
, dto.CashPriceVar
from (
select
tt.StoreNumber
, tt.ProductKey
, tt.DateKey
, max( dt.DateKey ) MaxDateKey
from #tt tt
inner join #dt dt
on dt.StoreNumber = tt.StoreNumber
and dt.ProductKey = tt.ProductKey
and dt.DateKey <= tt.DateKey
group by
tt.StoreNumber
, tt.ProductKey
, tt.DateKey
) dd
inner join #dt dto
on dto.StoreNumber = dd.StoreNumber
and dto.ProductKey = dd.ProductKey
and dto.DateKey = dd.MaxDateKey;
EDIT: Can anyone advise as to whether or not the SQL Server LEAD function might be a better choice--perhaps comparing the value of the current row with the value of the following row?

select results from two tables but choose one field over another

I have two tables.
tblEmployee tblExtraOrMissingInfo
id nvarchar(10) id nvarchar(10)
Name nvarchar(50) Name nvarchar(50)
PreferredName nvarchar(50)
UsePreferredName bit
The data (brief example)
tblEmployee tblExtraOrMissingInfo
id Name id Name PreferredName UsePreferredName
AB12 John PN01 Peter Tom 1
LM22 Lisa YH76 Andrew Andy 0
PN01 Peter LM22 Lisa Liz 0
LK655 Sarah
I want a query to produce the following result
id Name
AB12 John
LM22 Lisa
PN01 Tom
YH76 Andrew
LK655 Sarah
So what I want is all the records from tblEmployee returned and any records in tblExtraOrMissingInfo that are not already in tblEmployee.
If there is a record in both tables with the same id I would like is if the UsePreferredName field in tblExtraOrMissingInfo is 1 for the PreferredName to be used rather than the Name field in the tblEmployee, please see the record PN01 in the example above.
It is slightly faster to use a left join and coalesce than to use the case statement (most servers are optimized for coalesce).
Like this:
SELECT E.ID, COALESCE(P.PreferredName,E.Name,'Unknown') as Name
FROM tblemployee E
LEFT JOIN tblExtraOrMissingInfo P ON E.ID = P.ID AND P.UsePreferredName = 1
The ,'Unknown' is not needed to answer your question, but I added
here to show that you can enhance this query to handle cases where the
name is not available in both tables and you don't want nulls in your result
left join on the employee table and use a case expression for name.
select e.id
,case when i.UsePreferredName = 1 then i.PreferredName else e.name end as name
from tblemployee e
left join tblExtraOrMissingInfo i on i.id=e.id
You can LEFT OUTER JOIN the tables together, then use a CASE statement and COALESCE() formula to get this:
SELECT
tblEmployee.id,
CASE WHEN UsePreferredName = 1 THEN COALESCE(PreferredName, tblEmployee.Name) ELSE tblEmployee.name
FROM
tblEmployee
LEFT OUTER JOIN tblExtraOrMissingInfo
ON tblEmployee.id = tblExtraOrMissingInfo.id
CASE checks that usePreferredName value, and the COALESCE() then grabs PreferredName unless it's NULL. Then it grabs the employees name from tblEmployee.
select id ,name
from
(
select id ,name from tblEmployee
union all
select id ,name from tblExtraOrMissingInfo
)group by id,name
This is an other way you can achieve the results. You can also use CTE to get the same result.
CREATE TABLE #tblEmployee
(
id NVARCHAR(10)
, Name NVARCHAR(50)
);
CREATE TABLE #tblExtraOrMissingInfo
(
id NVARCHAR(10)
, Name NVARCHAR(50)
, PreferredName NVARCHAR(50)
, UsePreferredName BIT
);
INSERT INTO #tblEmployee
( id, Name )
VALUES ( N'AB12' -- id - nvarchar(10)
, N'John' -- Name - nvarchar(50)
),
( N'LM22' -- id - nvarchar(10)
, N'Lisa' -- Name - nvarchar(50)
),
( N'PN01' -- id - nvarchar(10)
, N'Peter' -- Name - nvarchar(50)
),
( N'LK655' -- id - nvarchar(10)
, N'Sarah' -- Name - nvarchar(50)
);
INSERT INTO #tblExtraOrMissingInfo
( id, Name, PreferredName, UsePreferredName )
VALUES ( N'PN01' -- id - nvarchar(10)
, N'Peter' -- Name - nvarchar(50)
, N'Tom' -- PreferredName - nvarchar(50)
, 1 -- UsePreferredName - bit
),
( N'YH76' -- id - nvarchar(10)
, N'Andrew' -- Name - nvarchar(50)
, N'Andy' -- PreferredName - nvarchar(50)
, 0 -- UsePreferredName - bit
),
( N'LM22' -- id - nvarchar(10)
, N'Lisa' -- Name - nvarchar(50)
, N'Liz' -- PreferredName - nvarchar(50)
, 0 -- UsePreferredName - bit
);
SELECT R.id
, CASE WHEN tbl.UsePreferredName = 1 THEN tbl.PreferredName
ELSE R.Name
END AS NAME
FROM #tblExtraOrMissingInfo tbl
RIGHT JOIN ( SELECT id
, Name
FROM #tblEmployee
UNION
SELECT id
, Name
FROM #tblExtraOrMissingInfo
) AS R
ON R.id = tbl.id
AND R.Name = tbl.Name;

Query Slow down due to structure of WHERE clause

I have a query that creates an #TABLE of a population of interest. It's structure is like this:
DECLARE #SepsisTbl TABLE (
PK INT IDENTITY(1, 1) PRIMARY KEY
, Name VARCHAR(500)
, MRN INT
, Account INT
, Age INT -- Age at arrival
, Arrival DATETIME
, Triage_StartDT DATETIME
, Left_ED_DT DATETIME
, Disposition VARCHAR(500)
, Mortality CHAR(1)
);
WITH Patients AS (
SELECT UPPER(Patient) AS [Name]
, MR#
, Account
, DATEDIFF(YEAR, AgeDob, Arrival) AS [Age_at_Arrival]
, Arrival
, Triage_Start
, TimeLeftED
, Disposition
, CASE
WHEN Disposition IN (
'Medical Examiner', 'Morgue'
)
THEN 'Y'
ELSE 'N'
END AS [Mortality]
FROM SMSDSS.c_Wellsoft_Rpt_tbl
WHERE Triage_Start IS NOT NULL
AND (
Diagnosis LIKE '%SEPSIS%'
OR
Diagnosis LIKE '%SEPTIC%'
)
)
INSERT INTO #SepsisTbl
SELECT * FROM Patients
From this point forward I have 5 more queries of the same sort that are looking for different types of orders that I then LEFT OUTER JOIN onto this table. My question is, why does my performance degrade so much when I change the where clause of the tables from this:
AND A.Account IN (
SELECT Account
FROM SMSDSS.c_Wellsoft_Rpt_tbl
WHERE (
Diagnosis LIKE '%SEPSIS%'
OR
Diagnosis LIKE '%SEPTIC%'
)
to this:
AND A.Account IN (
SELECT Account
FROM #SepsisTbl
)
The run time goes from 2.5 minutes to over 10 minutes with still no results. The CTE itself runs as fast as I can press F5.
Thank you,
I suspect that the problem is because the table variable doesn't have an index on Account. If you add an index on Account then I would expect better performance.
See the answer to this question for details on how to add an index: Creating an index on a table variable

SQL Delete specific records with condition

I have a table like below:
And the delete condition is:
delete from Employee only if the date is smaller than a specific date and no record is larger than that date
e.g.
if the date is 3/8/2014, then only record with EmployeeID 3 will be removed as the record with EmployeeID 4 has date larger than 3/8/2014, and EmployeeID 5 won't be removed as the date is 3/9/2014
if the date is 3/9/2014, then record with EmployeeID 3 and 5 will be removed, as the record with EmployeeID 4 has date larger than 3/9/2014
At first, I tried
delete from Employee where Date > #Date
But the above SQL would delete all records wherever the date is smaller than the #Date
What amendments should be made to the above SQL?
Try this:
DELETE FROM TableName
WHERE EmployeeID IN
(SELECT EmployeeID FROM TableName
GROUP BY EmployeeID
HAVING MAX(DATE)<=#Date)
Tested and verified.
See an example in SQL Fiddle.
Try this:
delete from Employee
where EmployeeID in
(select EmployeeID
from Employee
group by Employeeid
having max(Date) < #Date)
Here it is,
Declare #d date ='3/8/2014'
delete from myEmp where empID in
(
select empID from myEmp
group by empID
having MAX(empDate) <=#d
)
Link for Demo,
DEMO
create table #t (EmployeeID int, Date datetime)
insert #t values
(3, '20140304'),
(3, '20140305'),
(3, '20140306'),
(4, '20140307'),
(4, '20140308'),
(4, '20140310'),
(5, '20140309')
declare #date date = '20140308'
;with x as (
select t.*
from #t t
where Date <= #date and not exists (
select * from #t t2 where t.EmployeeId = t2.EmployeeID and Date > #date)
)
delete x;

order a record by date field's month

Hello I have a table in mssql 2008 that contains a date field.
I'd like to make a select statement which will list all members, sorted by month only.
how do I access only the month part of the date field?
here are some of the member table fields:
id varchar(9) primary key,
f_name varchar(20),
l_name varchar(20),
f_name_english varchar(20),
l_name_english varchar(20),
gender varchar(20),
experience int,
b_date date,
passport varchar(20),
You can also use month() function. (or datepart(month, b_date))
Select id, f_name, l_name....
From YourTableName
Order by month(b_date)
Try this one -
SELECT id
, f_name
, l_name
, f_name_english
, l_name_english
, gender
, experience
, b_date
, passport
FROM YOUR_TABLE
ORDER BY MONTH(b_date)
SELECT * FROM YOURTABLE T
ORDER BY DATEPART(MONTH,T.b_date)
Include DATEPART(YEAR,T.b_date) to ORDER BY if you want to order a result by year too
this will sort by year & month
SELECT
id, f_name, l_name....
FROM
YOUR_TABLE
ORDER BY
CONVERT(Nvarchar(7), b_date, 121)
--or use DatePart(Month, b_date)
-- if you don't care about the year.