How To Query Order By Desc StartDate But NULLS First - sql-server

sQL FIDDLE
CREATE TABLE [STUDENT_MASTER]
(
[User_ID] [int] IDENTITY (1, 1) NOT NULL CONSTRAINT STUDENT_MASTER_P_KEY PRIMARY KEY,
[Name] [varchar] (50),
[START_DATE] [varchar] (50),
[PRIORITY] [varchar] (50)
)
INSERT INTO STUDENT_MASTER
VALUES('JOHN','2013-08-16','4')
INSERT INTO STUDENT_MASTER
VALUES('JACK','2013-08-10','')
INSERT INTO STUDENT_MASTER
VALUES('MACK','','1')
INSERT INTO STUDENT_MASTER
VALUES('ACK','2013-08-15','2')
//SQL QUERY
SELECT ROW_NUMBER() OVER
(ORDER BY CASE
WHEN STUDENT_MASTER.START_DATE IS NULL THEN 1
WHEN STUDENT_MASTER.PRIORITY IS NULL THEN 1
ELSE 0 END,STUDENT_MASTER.START_DATE DESC ,STUDENT_MASTER.PRIORITY DESC
)AS RowNumber,STUDENT_MASTER.START_DATE
FROM STUDENT_MASTER
HOW TO QUERY ORDER BY DESC START DATE AND NULL VALUE BE FIRST

DEMO
ORDER BY
CASE WHEN START_DATE = '' THEN 0 ELSE 1 END ASC,
START_DATE DESC
You could use ISNULL, but your column does not have null values - it has empty strings intead.
And another problem - because your START_DATE column is VARCHAR, not DATETIME it will perform string, alphabetical sort instead of datetime sorting.

Don't simply order by StartDate, order by StartDate or a default value if it's null.
ORDER BY ISNULL(StartDate, '9999-12-31') DESC
Oh... and have your date be an actual datetime. Otherwise you'll just be doing an alphabetical sort.

Considering that is for purpose your date as string, this would be my solution for the problem
SELECT
start_date
FROM
STUDENT_MASTER
ORDER BY
LEN(start_date),
start_date DESC
Follows the SQL Fiddle

Related

SQL Server Joining record based on max 7 days old

The query that I've build does not fit the solution. I've tried many queries but can't get the result I want.
I have the following table
CREATE TABLE [dbo].[test](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ATC] [varchar](15) NOT NULL,
[PID] [varchar](7) NOT NULL,
[NAME] [varchar](50) NOT NULL,
[REG_DATE] [datetime] NULL,
[ACTIVE] [bit] NOT NULL CONSTRAINT [DF_test_ACTIVE] DEFAULT ((1))
) ON [PRIMARY]
Example data
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST1','2016-08-31 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST2','2016-09-01 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST3','2016-09-02 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST4','2016-09-03 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES('A01','123456','TEST5','2016-09-06 00:00:00.000',1);
Example Query:
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ATC, PID ORDER BY REG_DATE ASC) AS ROWNUM,* FROM [dbo].[test]
WHERE ACTIVE=0
)
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
LEFT JOIN CTE d2 ON d2.ATC = d1.ATC AND d2.PID = d1.PID
AND DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE) <= 7
WHERE d1.ACTIVE=1 AND d1.PID=123456;
Wanted result:
The record with column ACTIVE True (1) should contain (if the record exists) the REG_DATE of the not active previous record max 7 days old. Like:
(No column name) NAME ACTIVE_REC_DATE NOTACTIVE_REC_DATE ACTIVE ACTIVE
3 TEST5 2016-09-06 00:00:00.000 2016-08-31 00:00:00.000 1 0
Currently the query result contains multiple records because the are more records that will fall in the 7 days period. I need to join 1 record that will be the max 7 day old one.
I've used the ROW_NUMBER() with over partition by so I can use and identify the first record because I will be sorting ascending. This doesn't work when there is no previous records available or the previous records are older then 7 days
When there is no records to join is ignored can use INNER JOIN or date columns at null
I hope I'm clear with my explanation.
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
OUTER APPLY
(SELECT TOP 1 T1.* FROM dbo.test t1 WHERE t1.ATC = d1.ATC AND t1.PID = d1.PID and DATEDIFF(DAY, t1.REG_DATE, d1.REG_DATE) <= 7 order by t1.REG_DATE desc) d2
WHERE d1.ACTIVE=1 AND d1.PID=123456;
You can return a single row for a PID by adding a filter on ROWNUM to your left join:
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ATC, PID ORDER BY REG_DATE ASC) AS ROWNUM,* FROM [dbo].[test]
WHERE ACTIVE=0
)
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
LEFT JOIN CTE d2 ON d2.ATC = d1.ATC AND d2.PID = d1.PID
AND DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE) <= 7
AND d2.ROWNUM = 1
WHERE d1.ACTIVE=1 AND d1.PID=123456;
It's not clear from the question how the query should behave when no previous records from the last seven days exist.

Error MSG 213 Column name or number of supplied values does not match table definition

Hi I'm trying to append the result of my query to another table, but i get the an error, here is my code for the project
--create new table
create table tempweblogs
(
date1 datetime
users nvarchar(50)
utotal int
date2 datetime
hostname nvarchar(50)
htotal int
date3 datetime
srcip nvarchar(50)
stotal int
)
--insert query result to tempweblogs table
insert into tempweblogs
SELECT distinct top 10
Xdate as date1, Xuser as users, count (Xuser) as utotal
from weblogs
where Xdate='2/16/2016' and Xuser is not null
group by Xuser, Xdate order by utotal DESC
SELECT distinct top 10
Xdate as date2, Xhostname as hostname, count(Xhostname) as htotal
from weblogs
where Xdate='2/16/2016' and xhostname is not null
group by Xhostname, Xdate order by htotal DESC
SELECT distinct top 10
Xdate as date3, Xsrcip as srcip, count (Xsrcip) as stotal
from weblogs
where Xdate='2/16/2016' and Xuser is not null
group by Xsrcip, Xdate order by stotal DESC
You should need to specify the column list in the INSERT statement
insert into tempweblogs ( date1 , users , utotal )
select ....
also you need the INSERT clause for all 3 query

T-SQL UNION between two queries with different order by, all orded by

As the title I have this problem:
I have these two queries
SELECT state, TIMESTAMP
FROM myTable
WHERE state != 9
ORDER BY TIMESTAMP ASC
SELECT TOP (3) state, TIMESTAMP
FROM myTable
WHERE state = 9
ORDER BY TIMESTAMP DESC
is it possible to ORDER BY again (ORDER BY TIMESTAMP ASC) the UNION of these queries?
Thank you
EDIT: to be more specific
I have a table with [state] and [timestamp] fields. [State] value can be 3, 8 or 9.
What I need is to select:
[state] = 9 last 3 records
[state] != 9 all
all ORDER BY [timestamp] ASC
You can do this:
SELECT [state], [TIMESTAMP]
FROM
(
SELECT [state], [TIMESTAMP]
FROM myTable
WHERE [state] != 9
UNION
SELECT TOP(3) [state], [TIMESTAMP]
FROM myTable
WHERE [state] = 9
ORDER BY [TIMESTAMP] DESC
) u
ORDER BY [TIMESTAMP] ASC
The order by of the first query is redundant in the union, but the second query needs it for the top(3), otherwise you get 3 arbitrary rows.
Please try like this
SELECT *
FROM (
SELECT state, TIMESTAMP
FROM myTable
WHERE state != 9
UNION
SELECT TOP (3) state, TIMESTAMP
FROM myTable
WHERE state = 9
ORDER BY (CASE WHEN state = 9 THEN TIMESTAMP END ) DESC
,(CASE WHEN state != 9 THEN TIMESTAMP END ) ASC
) D

low query execution time SQL server

I have this query in sql server database
SELECT [Id]
,[CreatedBy]
,[CreatedDate]
,[ModifiedBy]
,[ModifiedDate]
,[IsDeleted]
,[IsActive]
,[Type]
,[RelaseDate]
,[Prefix]
,[SubTitle]
,[Title]
,[Status]
,[Sequence]
,[Value]
,[Content]
,[Author]
,[Summery]
,[EndDate]
,[ViewedTime]
,[DefaultCategorieId]
,[URLTitle]
,[AlowComments]
,[HideImage]
,[ExternalLink]
FROM [SalesItem].[dbo].[Items]
where Type='7a38bd0c-222f-4308-8dce-f7a2014d7d79' and IsDeleted <> 1
order by [CreatedDate] desc
OFFSET 10 ROWS
FETCH NEXT 20 ROWS ONLY;
the items has about 200,000 record the execution time for this query is about 00:80:30
Is there any way to faster the query. because the same table may have many different queries which they take longer execution time
Considering [Id] as PK with identity enabled and NO index on CreatedDate, You can sort by [ID]
As ordering by both columns will be same. (Hope you are not updating CreatedDate later)
This query should be quicker
;with cte
as
(
SELECT ROW_NUMBER() over (order by [Id]) as rowid,
,[Id]
,[CreatedBy]
,[CreatedDate]
,[ModifiedBy]
,[ModifiedDate]
,[IsDeleted]
,[IsActive]
,[Type]
,[RelaseDate]
,[Prefix]
,[SubTitle]
,[Title]
,[Status]
,[Sequence]
,[Value]
,[Content]
,[Author]
,[Summery]
,[EndDate]
,[ViewedTime]
,[DefaultCategorieId]
,[URLTitle]
,[AlowComments]
,[HideImage]
,[ExternalLink]
FROM [SalesItem].[dbo].[Items]
where Type='7a38bd0c-222f-4308-8dce-f7a2014d7d79' and IsDeleted <> 1
)
select * from cte where rowid between 11 and 20
Please let me know the execution time this takes

calculate attendance and mark absentees for each day MS SQL

this is a table for attendance logs:
CREATE TABLE [dbo].[DeviceLogs] (
[DeviceLogId] INT NOT NULL,
[UserId] NVARCHAR (50) NOT NULL,
[LogDate] DATETIME NOT NULL,
);
this is my employee table:
CREATE TABLE [dbo].[Employees] (
[EmployeeId] INT IDENTITY (1, 1) NOT NULL,
[EmployeeName] NVARCHAR (50) NULL,
[UserId] NVARCHAR (50) NOT NULL,
[Gender] NVARCHAR (255) NULL,
[DepartmentId] NVARCHAR (255) NULL,
[Designation] NVARCHAR (255) NULL,
[CategoryId] INT NULL,
[DOJ] DATETIME NULL,
[DOR] DATETIME NULL,
[Status] NVARCHAR (255) NULL,
[DOB] DATETIME NULL,
);
We will insert attendance logs in the first table.
Now i want to calculate attendance for each employee in each day.
SELECT [userid] AS identit,
CONVERT(VARCHAR, userid),
Min(logdate) AS lowtime,
Max(logdate) AS hightime,
CONVERT(VARCHAR, Max(logdate) - Min(logdate), 108) AS dur,
CASE
WHEN CONVERT(VARCHAR, Max(logdate) - Min(logdate), 108) IS NOT NULL
THEN
'present'
ELSE 'Absent'
END AS Status
FROM [dbo].[devicelogs]
GROUP BY [userid]
ORDER BY userid DESC
This is the MS SQl query which i'm using.
But it is giving me result only if the person has attendance logs.
I want to calculate attendance even in the person is absent.
I want it to repeat it for everyday.
Please help me here.
If am not wrong there should be a User table which contains the list of all the users.
You have to Left/Right outer join the User table with devicelogs table.
Something like this.
SELECT U.[userid] AS identit,
CONVERT(VARCHAR, U.userid),
Min(logdate) AS lowtime,
Max(logdate) AS hightime,
CONVERT(VARCHAR, Max(logdate) - Min(logdate), 108) AS dur,
CASE
WHEN d.userid IS NOT NULL THEN 'present'
ELSE 'Absent'
END AS Status
FROM [users] U -- Replace with the table that contains all the users
LEFT OUTER JOIN [dbo].[devicelogs] D
ON U.userid = D.userid
GROUP BY [userid]
ORDER BY U.userid DESC
To get daily reports / lists it's usually best to have a date table that contains all the possible dates you'll ever need, for example 1.1.2000 - 31.12.2099. Using it you can easily create a query that groups by that date, like this:
SELECT
e.userid,
d.[date],
l.first,
l.last,
case when l.first is null then 'Absent' else 'Present' end as status
FROM
[dbo].[Employees] e
cross join [dbo].[Dates] d
outer apply (
select min(logdate) as first, max(logdate) as last
from [dbo].[devicelogs] l
where l.userid = e.userid and
l.logdate >= d.[date] and l.logdate < dateadd(day, 1, d.[date]
) l
where d.[date] >= '20150501' and d.[date] < getdate()
GROUP BY e.userid, d.[date]
ORDER BY e.userid desc, d.[date] desc
You could do it of course with devicelog too, but if there's ever a single date without any logs you'll miss that completely.
Didn't try this, hopefully there's no errors :)
First of all you must clarify why the log table may have some users with no log date because the logdate is set to NOT NULL and you are quering log table and expecting to get some users with no logdate.
The algorithm is : When a employee is not in the log table set him as absent and put the duration equal to 0 . Otherwhise calculate the duration and set him as present . Plus get his frist date of log and last date of log.
1) Get a table showing users with null dates
select E.UserID as UserID,L.LogDate as logdate from employee E
full outer join
DeviceLogs L
on E.UserID=L.UserID
2) apply your code to this table

Resources