SQL Counting non numeric values from a column - sql

I have a table named tasks inside is
id
tasks
tasks_status
task_date
The tasks statuses are "done","pending","forwarded","cancelled".
How can I query the table of counting all the done, all the pending, all the forwarded and all cancelled.
I tried doing all the tweaks from COUNT but to no avail. It's been 2 hours of looking for a way. Please help
My goal is to specifically count only those DONE, I can get the count of all the specifics but just would need to show the total count of done (for example)

Group by is better but if you just want the ones specified as 'Done' the below should work.
SELECT COUNT(*) FROM TASTS WHERE TASKS_STATUS='done'

Select what you want with count and Group Them.
SELECTS tasks_status, count(tasks_status) FROM status GROUP BY tasks_status;

select tasks_status, count(*) from tasks group by tasks_status
http://sqlfiddle.com/#!17/1e27e/4/0

If you want to get all counts then you need to use group by but if you want to get count of just one item then group by is not required.
Following is query to generate scenario
CREATE TABLE [dbo].[tasks](
[id] [int] IDENTITY(1,1) NOT NULL,
[tasks] [varchar](50) NULL,
[tasks_status] [varchar](50) NULL,
[task_date] [date] NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[tasks] ON
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (1, N'task1', N'pending', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (2, N'task2', N'forwarded', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (3, N'task3', N'pending', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (4, N'task4', N'done', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (5, N'task5', N'done', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (6, N'task6', N'cancelled', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (7, N'task7', N'done', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (8, N'task8', N'forwarded', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (9, N'task9', N'pending', CAST(N'2022-09-30' AS Date))
GO
INSERT [dbo].[tasks] ([id], [tasks], [tasks_status], [task_date]) VALUES (10, N'task10', N'done', CAST(N'2022-09-30' AS Date))
GO
SET IDENTITY_INSERT [dbo].[tasks] OFF
GO
You can use group by if you want to get count of all unique tasks_status or some of tasks_status using following query
For All
SELECT tasks_status, count(tasks_status) FROM dbo.tasks GROUP BY tasks_status;
For done and pending
SELECT tasks_status, count(tasks_status) FROM dbo.tasks
WHERE tasks_status IN ('done','pending')
GROUP BY tasks_status
if you want to get count for done only then you can use either of the following. Use group by if you want to use other columns in select, else if you want to get just count and no other column then just 2nd query without group by
SELECT tasks_status, count(tasks_status) FROM dbo.tasks
WHERE tasks_status = 'done'
GROUP BY tasks_status
or
SELECT COUNT(tasks_status) FROM dbo.tasks WHERE tasks_status='done'

Related

How to return "most populated","least populated" countries grouped by continent organized in a single table via SQL?

This is a variant of the SQLzoo tutorial.
'world' table contains fields
'population'(assigned to each country),
'name' (all countries) and
'continent' (assigned to each country).
Expected output is a table as shown below
Continent
Most_populous
Least_populous
Africa
Ghana
xyz
Asia
China
abc
I did try a complicated function as below, but was not able to get it to work due to "SQL error". Not sure why.
SELECT DISTINCT continent
, (SELECT x.name
FROM world x
WHERE x.population = (SELECT max(y.population)
FROM world y
WHERE x.continent = y.continent)) AS most_populous
, (SELECT z.name
FROM world z
WHERE z.population = (SELECT min(a.population)
FROM world a
WHERE a.continent=z.continent)) AS least_populous FROM world;
Is there an easier way to get the required output?
You can try this:
SELECT world.continent,
(SELECT x.name
FROM world x
WHERE x.population = (SELECT max(y.population)
FROM world y
WHERE x.continent = y.continent)
AND world.continent = x.continent
) AS most_populous,
(SELECT z.name
FROM world z
WHERE z.population = (SELECT min(a.population)
FROM world a
WHERE z.continent = a.continent)
AND world.continent = z.continent
) AS least_populous
FROM world
GROUP BY world.continent;
Thank you
Since I did not had the tables with me, I ended up creating one. It would be better if you could include table and data creation scripts in question. Second, this is going to be a fairly small table so I am not going to worry about performance. I would create a view based on this query and that will be good enough.
Table creation scripts:
USE [StackOverflow]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CountryPopulation]') AND type in (N'U'))
DROP TABLE [dbo].[CountryPopulation]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[CountryPopulation](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Continent] [nvarchar](max) NULL,
[Population] [int] NULL,
CONSTRAINT [PK_CountryPopulation] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
USE [StackOverflow]
GO
SET IDENTITY_INSERT [dbo].[CountryPopulation] ON
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (1, N'C1', N'Asia', 100)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (2, N'C2', N'Asia', 200)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (3, N'C3', N'Asia', 300)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (4, N'C4', N'Europe', 100)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (5, N'C5', N'Europe', 200)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (6, N'C6', N'Europe', 300)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (7, N'C7', N'Africa', 100)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (8, N'C8', N'Africa', 200)
GO
INSERT [dbo].[CountryPopulation] ([ID], [Name], [Continent], [Population]) VALUES (9, N'C9', N'Africa', 200)
GO
SET IDENTITY_INSERT [dbo].[CountryPopulation] OFF
GO
Query to get result:
SELECT MinMax.Continent,
ForLeast.[name] AS LeastPopulous,
ForMost.[name] AS MostPopulous
FROM CountryPopulation ForMost JOIN
CountryPopulation ForLeast JOIN
( SELECT DISTINCT Continent,
MIN([population]) OVER(PARTITION BY continent) AS LeastPopulation,
MAX([population]) OVER(PARTITION BY continent) AS MaxPopulation
FROM CountryPopulation) MinMax
ON ForLeast.Continent = MinMax.Continent AND ForLeast.[Population] = MinMax.LeastPopulation
ON ForMost.Continent = MinMax.Continent AND ForMost.[Population] = MinMax.MaxPopulation
Note the results for Africa. There are 2 rows. It is possible for more than one country to have least or most population. You would want to think on how to handle that scenario.

Find non existing time intervall when doing join to another table

I have a question that I dont know If there is solution to in sql. Made an small example
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Events](
[Id] [int] IDENTITY(1,1) NOT NULL,
[EventTime] [datetime] NOT NULL,
[Event] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Logging] Script Date: 2020-07-07 14:35:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Logging](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FromTime] [datetime] NOT NULL,
[ToTime] [datetime] NOT NULL,
[Status] [nvarchar](50) NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Events] ON
GO
INSERT [dbo].[Events] ([Id], [EventTime], [Event]) VALUES (1, CAST(N'2020-07-07T14:14:00.000' AS DateTime), N'str')
GO
INSERT [dbo].[Events] ([Id], [EventTime], [Event]) VALUES (2, CAST(N'2020-07-07T07:01:00.000' AS DateTime), N'testcall')
GO
INSERT [dbo].[Events] ([Id], [EventTime], [Event]) VALUES (3, CAST(N'2020-07-07T15:22:00.000' AS DateTime), N'ipfail')
GO
SET IDENTITY_INSERT [dbo].[Events] OFF
GO
SET IDENTITY_INSERT [dbo].[Logging] ON
GO
INSERT [dbo].[Logging] ([Id], [FromTime], [ToTime], [Status]) VALUES (1, CAST(N'2020-07-07T01:00:00.000' AS DateTime), CAST(N'2020-07-07T13:00:00.000' AS DateTime), N'All well')
GO
INSERT [dbo].[Logging] ([Id], [FromTime], [ToTime], [Status]) VALUES (2, CAST(N'2020-07-07T13:01:00.000' AS DateTime), CAST(N'2020-07-07T15:00:00.000' AS DateTime), N'All well')
GO
INSERT [dbo].[Logging] ([Id], [FromTime], [ToTime], [Status]) VALUES (3, CAST(N'2020-07-07T15:33:00.000' AS DateTime), CAST(N'2020-07-07T20:00:00.000' AS DateTime), N'All well')
GO
INSERT [dbo].[Logging] ([Id], [FromTime], [ToTime], [Status]) VALUES (4, CAST(N'2020-07-07T20:01:00.000' AS DateTime), CAST(N'2020-07-07T23:00:00.000' AS DateTime), N'All well')
GO
SET IDENTITY_INSERT [dbo].[Logging] OFF
GO
When doing an inner join of this table I want to find the Event in Event table that doesn't have a matching timeframe in Logging. The timeframe that's missing is 15:00 to 15:33 and the event that happens that happens is the Event with ID 3. Everything is measured in minutes. Is this possible? Or have to do it some other way?
If I understand correctly, you want not exists:
select l.*
from logging l
where not exists (select 1
from events e
where e.eventtime >= l.fromtime and
e.eventtime <= l.totime
);
However, this returns two timeframes -- ones with ids 3 and 4.
Here is a db<>fiddle.

SQL Recursive Count

I have two tables I am joining with the following structure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ContentDivider](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentId] [int] NULL,
[Name] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_ContentDivider] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[CustomPage] Script Date: 23-03-2020 17:46:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[CustomPage](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ContentDividerId] [int] NOT NULL,
[Name] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_CustomPage] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
A ContentDivider can have n ContentDividers as Children and can have m CustomPages as children as well.
I want a View that counts the Display the current CustomDivider and the COunt for all the CustomPages as Children of the current ContentDivider.
My Test data:
SET IDENTITY_INSERT [dbo].[ContentDivider] ON
GO
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (1, NULL, N'TopLevel1')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (2, NULL, N'TopLevel2')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (3, NULL, N'TopLevel3')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (4, 1, N'SecondLevel1')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (5, 1, N'SecondLevel2')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (6, 1, N'SecondLevel3')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (7, 4, N'ThirdLevel1')
INSERT [dbo].[ContentDivider] ([Id], [ParentId], [Name]) VALUES (8, 4, N'ThirdLevel2')
GO
SET IDENTITY_INSERT [dbo].[ContentDivider] OFF
GO
SET IDENTITY_INSERT [dbo].[CustomPage] ON
GO
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (1, 1, N'Level1_1')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (2, 1, N'Level1_2')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (3, 2, N'Level1_3')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (4, 2, N'Level1_4')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (5, 4, N'Level1_5')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (6, 5, N'Level1_6')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (7, 7, N'Level1_7')
INSERT [dbo].[CustomPage] ([Id], [ContentDividerId], [Name]) VALUES (8, 8, N'Level1_8')
GO
SET IDENTITY_INSERT [dbo].[CustomPage] OFF
GO
And the View I want to extend:
SELECT dbo.ContentDivider.ParentId, dbo.ContentDivider.Name, dbo.ContentDivider.Id, COUNT(DISTINCT dbo.CustomPage.Id) AS CustomPageCount
FROM dbo.ContentDivider LEFT OUTER JOIN
dbo.CustomPage ON dbo.ContentDivider.Id = dbo.CustomPage.ContentDividerId
GROUP BY dbo.ContentDivider.ParentId, dbo.ContentDivider.Name, dbo.ContentDivider.Id
As for now the view counts the custompages directly underneath the contentdivider. I would like all the CustomPages as children counted.
Any suggestions?
The respected result would be:
View
this sounds like a perfect situation for recursive cte ;)
So, if I understood correctly, your expected result would be Toplevel1 with 6 pages and Toplevel 2 with 2 pages since all the other levels are somewhere beneath these two mentioned levels?
The cte might look something like this (maybe you habe to include the max recursion option):
WITH cte AS(
SELECT 1 lvl, ID AS ParentID, ID, Name
FROM dbo.ContentDivider cd
WHERE ParentId IS NULL
UNION ALL
SELECT c.lvl+1 AS lvl, c.ParentID, cd.ID, cd.Name
FROM dbo.ContentDivider cd
INNER JOIN cte c ON cd.ParentID = c.ID
)
SELECT c.ParentID, cd.Name, COUNT(DISTINCT cp.Id) AS CustomPageCount
FROM cte c
JOIN dbo.ContentDivider cd ON cd.ID = c.ParentID
LEFT OUTER JOIN dbo.CustomPage cp ON cp.ContentDividerId = c.id
GROUP BY c.ParentId, cd.Name
This leads to all pages being assigned to its top level.
See fiddle for details: http://sqlfiddle.com/#!18/f1a44/28/1
Edit: Since you need the details down to DividerID, I extended my example in the fiddle. First of all, I fetch the PageCount per ID in one cte and additionally the PageCount aggregated on level (ParentID and all its IDs) - this done you don't need the count and grouping in the following ctes.
In my query I then check, if my current rows ID is a top-level of any kind and assign the corresponding PageCount to this row.
WITH cteCnt AS(
SELECT cd.ID, COUNT(DISTINCT cp.Id) AS CustomPageCount
FROM dbo.ContentDivider cd
LEFT OUTER JOIN dbo.CustomPage cp ON cp.ContentDividerId = cd.id
GROUP BY cd.ID
),
cteTop AS(
SELECT cd.ID, COUNT(DISTINCT cp.Id) AS CustomPageCount
FROM dbo.ContentDivider cd
LEFT OUTER JOIN dbo.CustomPage cp ON cp.ContentDividerId = cd.id
GROUP BY cd.ID
UNION ALL
SELECT cd.ParentID, COUNT(DISTINCT cp.Id) AS CustomPageCount
FROM dbo.ContentDivider cd
LEFT OUTER JOIN dbo.CustomPage cp ON cp.ContentDividerId = cd.id
WHERE cd.ParentID IS NOT NULL
GROUP BY cd.ParentID
),
cteTopSum AS(
SELECT ID, SUM(CustomPageCount) AS CustomPageCount
FROM ctetop
GROUP BY ID
),
cte AS(
SELECT 1 lvl, cd.ID AS ParentID, cd.ID AS ParentIDx, cd.ID, cd.Name, cnt.CustomPageCount
FROM dbo.ContentDivider cd
INNER JOIN cteCnt cnt ON cnt.ID = cd.ID
WHERE ParentId IS NULL
UNION ALL
SELECT c.lvl+1 AS lvl, c.ParentID, cd.ParentID AS ParentIDx, cd.ID, cd.Name, cnt.CustomPageCount
FROM dbo.ContentDivider cd
INNER JOIN cteCnt cnt ON cnt.ID = cd.ID
INNER JOIN cte c ON cd.ParentID = c.ID
),
cteOut AS(
SELECT *
,SUM(CustomPageCount) OVER (PARTITION BY ParentID) x
,SUM(CustomPageCount) OVER (PARTITION BY ParentIDx) y
FROM cte c
)
SELECT CASE WHEN co.ParentIDx = co.ID THEN NULL ELSE co.ParentIDx END AS ParentID, co.ID, co.Name, CASE WHEN co.ID = co.ParentID THEN co.X ELSE ts.CustomPageCount END CustomPageCount
FROM cteOut co
LEFT JOIN cteTopSum ts ON ts.ID = co.ID
ORDER BY 1, 2
See new fiddle for details: http://sqlfiddle.com/#!18/f1a44/185/1
I'm mot sure, if there is a prettier / nicer way to solve this, but seemingly this seems to solve the problem.
However, I did NOT check if it works if any number of sublevels or whatsoever - if you find any issues, feel free to comment.

Top three records for each branch

I need to write query for top three record(count and sum) for each branch of company and I have branch costumers and contracts tables
First of all, create a table like this:
CREATE TABLE [dbo].[Branches](
[Id] [int] NOT NULL,
[CompanyId] [int] NULL,
[Something] [int] NULL,
CONSTRAINT [PK_Table_5] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Then, insert some data into it:
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (1, 1, 10)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (2, 1, 15)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (3, 1, 20)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (4, 1, 25)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (5, 1, 22)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (6, 2, 50)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (7, 2, 32)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (8, 2, 30)
GO
INSERT [dbo].[Branches] ([Id], [CompanyId], [Something]) VALUES (9, 2, 10)
GO
In the end, your query will be like this:
SELECT result.Companyid, SUM(result.Something) [Sum], (SELECT COUNT(*) FROM Branches WHERE CompanyId = result.companyid) AS [Count]
FROM (
SELECT companyid, Something, Rank()
OVER (PARTITION BY CompanyId
ORDER BY id DESC ) AS Rank
FROM Branches
) result WHERE Rank <= 3
GROUP BY CompanyId
Schema:
First data:
Result:

Difference between TOP X and Row_Number()

Recently I've faced weird issue. I have two simple queries where one of them uses TOP X and other one does the same by using ROW_NUMBER and then selects items with rowNumber between 1 and X, and both of them ordered by same column, but the result is completely different.
For example, let's say we have a simple DB as below with some dummy data:
CREATE TABLE [dbo].[Test](
[Id] [int] IDENTITY(1,1) NOT NULL,
[NDate] [datetime] NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET IDENTITY_INSERT [dbo].[Test] ON
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (1, '2011-08-24 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (2, '2011-08-24 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (3, '2011-08-24 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (4, '2011-08-24 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (5, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (6, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (7, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (8, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (9, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (10, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (11, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (12, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (13, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (14, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (15, '2011-08-21 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (16, '2011-08-21 00:00:00.000')
SET IDENTITY_INSERT [dbo].[Test] OFF
Now if we perform below queries, we will get different results. If we use TOP 10, we will get below result:
SELECT TOP 10 [Id],[NDate] FROM [Test] order by NDate desc
RESULT=>
Id NDate
4 2011-08-24 00:00:00.000
3 2011-08-24 00:00:00.000
2 2011-08-24 00:00:00.000
1 2011-08-24 00:00:00.000
11 2011-08-21 00:00:00.000
10 2011-08-21 00:00:00.000
9 2011-08-21 00:00:00.000
8 2011-08-21 00:00:00.000
7 2011-08-21 00:00:00.000
6 2011-08-21 00:00:00.000
select id,NDate from (
select ROW_NUMBER() over (order by NDate DESC) as RNumber, Id,NDate
from Test) as t
where RNumber between 1 and 10
RESULT=>
id NDate
1 2011-08-24 00:00:00.000
2 2011-08-24 00:00:00.000
3 2011-08-24 00:00:00.000
4 2011-08-24 00:00:00.000
5 2011-08-21 00:00:00.000
6 2011-08-21 00:00:00.000
7 2011-08-21 00:00:00.000
8 2011-08-21 00:00:00.000
9 2011-08-21 00:00:00.000
10 2011-08-21 00:00:00.000
The issue is, When you are using LINQ to SQL, and you want to do pagination, generated query for selecting first page will be TOP X, while for the other pages will be using ROW_NUMBER, and the result is, some items will never appear in the listing.
You need to implement a secondary sorting.
Example:
select id,NDate from (
select ROW_NUMBER() over (order by NDate DESC, id) as RNumber, Id,NDate -- Note: NDate DESC, id
from Test) as t
where RNumber between 1 and 10
Example:
SELECT TOP 10 [Id],[NDate] FROM [Test] order by NDate desc, ID -- Note: NDate DESC, id
Otherwise, you might as well expect random records per unique NDate.
If you want the same records for each query, you have to specify that secondary sort column.
I agree with #hamlin11, but putting it more simply :-)
In the first example you are sorting by
order by NDate desc
/* to get same results as example 2, change this to
order by NDate desc, id
*/
and in the second by
order by NDate DESC, id
In the second example you are sorting by Id, that is why the ID column is in order, you haven't done this in the first example.
It might be better to use data like this, so you can see more clearly what is happening:
/****** Object: Table [dbo].[Test] Script Date: 08/27/2011 07:56:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Test](
[Id] [int] IDENTITY(1,1) NOT NULL,
[NDate] [datetime] NOT NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Test] ON
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (1, '2011-08-10 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (2, '2011-08-11 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (3, '2011-08-12 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (4, '2011-08-13 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (5, '2011-08-14 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (6, '2011-08-15 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (7, '2011-08-16 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (8, '2011-08-31 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (9, '2011-08-30 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (10, '2011-08-29 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (11, '2011-08-28 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (12, '2011-08-27 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (13, '2011-08-26 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (14, '2011-08-25 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (15, '2011-08-24 00:00:00.000')
INSERT [dbo].[Test] ([Id], [NDate]) VALUES (16, '2011-08-23 00:00:00.000')
SET IDENTITY_INSERT [dbo].[Test] OFF