I have a SQL Server Table like this :
id(autoincrement)
hostname(varchar)
group(varchar)
member(varchar)
datequeried(varchar)
The table is filled by a scheduled job that scans network for windows client PCs local admin group members.
Network scans -
seams with the fact that it may happen that some of the stations are not available during scans.
The query that I'd like to write is :
"select every hostname having the latest datequeried"
This is to display the newest result (rows) of each hostname queried on network.
Is it clear ?
I'm still facing some syntax issues and I'm sure it is quite easy.
Thanks in advance.
If you're on SQL SErver 2005 or newer (you didn't specify...), you can use a CTE to do this:
;WITH MostCurrent AS
(
SELECT
id, hostname, group,
member, datequeried,
ROW_NUMBER() OVER(PARTITION BY hostname ORDER BY datequeried DESC) 'RowNum'
FROM
dbo.YourTable
)
SELECT *
FROM MostCurrent
WHERE RowNum = 1
The inner SELECT inside the CTE "partitions" your data by hostname, e.g. each hostname gets a new "group" of data, and it numbers those entries starting at 1 for each group. Those entries are numbered by datequeried DESC, so the most recent one has the RowNum = 1 - for each group of data (e.g. for each hostname).
From SQL 2005 and later, you can use ROW_NUMBER() like this:
;WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY hostname ORDER BY datequeried DESC) AS RowNo
FROM YourTable
)
SELECT * FROM CTE WHERE RowNo = 1
"CTE" is a Commom Table Expression, basically just aliasing that first SELECT which I can then use in the 2nd query.
This will return 1 row for each hostname, with the row returned for each being the one
I can display the required results using :
select hostname, member, max(lastdatequeried)
as lastdatequeried
from members
group by hostname, member order by hostname
Thanks to all who helped.
select hostname,
max(datequeried) as datequeried
from YourTable
group by hostname
SELECT TOP 1 WITH TIES *
FROM YourTable
ORDER BY ROW_NUMBER() OVER(PARTITION BY hostname ORDER BY datequeried DESC)
Do you want to find each station's most recent scan?
Or do you want to find every station that was online (or not online) during the most recent scan?
I'd have a master list of workstations, first of all. Then I'd have a master list of scans. And then I'd have the scans table that holds the results of the scans.
To answer #1, you'd would use a subquery or inline view that returns for each workstation its id and max(scandate) and then you'd join that subquery back to scans table to pull out the scan row for that workstation id whose scandate matched its max(scandate).
To answer #2, you'd look for all workstations where exists a record (or where not exists a record, mutatis mutandis) in the scans table where scandate = the max(date) in the master scans list.
Related
In my table I have the columns id, userId and points. As a result of my query I would like to have the id of the record that contains the highest points, per user.
In my experience (more with MySQL than SQL Server) I would use the following query to get this result:
SELECT id, userId, max(points)
FROM table
GROUP BY userId
But SQL Server does not allow this, because all columns in the select should also be in the GROUP BY or be an aggregate function.
This is a hypothetical situation. My actual situation is a lot more complicated!
Use ROW_NUMBER window function in SQL Server
Select * from
(
select Row_Number() over(partition by userId Order by points desc) Rn,*
From yourtable
) A
Where Rn = 1
We have multiple MSSQL servers that has the same copy of a database, the below query returns valid order for all servers except one, I double checked the design of the tables and all looks identical except couple of servers are missing an index.
The query is generated by doctrine
WITH dctrn_cte AS (
SELECT TOP 10 a0_.Priority
FROM PROJECTS a0_
WHERE a0_.ProjectID = 1234
AND (a0_.Check1 > 0
OR
a0_.Check2 > 0)
AND a0_.Active = 1
ORDER BY a0_.Priority DESC)
SELECT *
FROM (
SELECT *, ROW_NUMBER()
OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte
) AS doctrine_tbl
WHERE doctrine_rownum BETWEEN 1 AND 10 ORDER BY doctrine_rownum ASC
Every time the query is executed on that particular server, it gives a random order - it is completely ignoring the ORDER BY part.
your query has one final ORDER BY clause: doctrine_rownum. This is an alias for a column that is an undetermined value:
ROW_NUMBER()
OVER (ORDER BY (SELECT 0)) AS doctrine_rownum
Therefore any order of the result is a correct order. All your servers return the correct result. Select isn't broken.
PS. You also have an ORDER BY inside the CTE, that is irrelevant to the final order, as it does not impose any order on the final result nor on the doctrine_rownum value.
The query is generated by doctrine
The query is generated incorrectly by doctrine, whatever this doctrine is.
Adding OPTION (MAXDOP 1) fixed the order on that server.
I'm try to select a certain rows from my table using the row_number over. However, the sql will prompt the error msg "Invalid column name 'ROWNUMBERS' ". Anyone can correct me?
SELECT ROW_NUMBER() OVER (ORDER BY Price ASC) AS ROWNUMBERS, *
FROM Product
WHERE ROWNUMBERS BETWEEN #fromCount AND #toCount
Attempting to reference the aliased column in the WHERE clause does not work because of the logical query processing taking place. The WHERE is evaluated before the SELECT clause. Therefore, the column ROWNUMBERS does not exist when WHERE is evaluated.
The correct way to reference the column in this example would be:
SELECT a.*
FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Price ASC) AS ROWNUMBERS, *
FROM Product) a
WHERE a.ROWNUMBERS BETWEEN #fromCount AND #toCount
For your reference, the order for operations is:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
There is another answer here that solves the specific error reported. However, I also want to address the wider problem. It looks a lot like what you are doing here is paging your results for display. If that is the case, and if you can use Sql Server 2012, there is a better way now. Take a look at OFFSET/FETCH:
SELECT First Name + ' ' + Last Name
FROM Employees
ORDER BY First Name
OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY;
That would show the third page of a query where the page size is 5.
In below query, I am using GROUP BY clause to get list of recently updated records depends on updated date. But I would like to have the query without a GROUP BY clause because of some internal reasons. Can please any one help me to solve this.
SELECT Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress PP
WHERE Proj_UpdatedDate IN (SELECT MAX(Proj_UpdatedDate)
FROM ProjectProgress
GROUP BY
Proj_ProjectID)
ORDER BY
Proj_ProjectID
Using TOP 1 should give you the same result assuming you meant the MAX(Proj_UpdatedDate):
SELECT Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress PP
WHERE Proj_UpdatedDate IN (SELECT TOP 1 Proj_UpdatedDate
FROM ProjectProgress
ORDER BY Proj_UpdatedDate DESC)
ORDER BY
Proj_ProjectID
However your query actually returns multiple dates since it's GROUPED BY Proj_ProjectId (the max date for each project). Is that your desired outcome - to show a list of dates that the projects were updated and by whom?
If so, try using ROW_NUMBER():
SELECT Proj_UpdatedDate, Proj_UpdatedBy
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY Proj_ProjectID ORDER BY Proj_UpdatedBy DESC) rn,
Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress
) t
WHERE rn = 1
And here is the SQL Fiddle. This assumes you are running SQL Server 2005 or greater.
Good luck.
I've been trying to replicate the limit and range feature provided in MySql in SQL Server with no luck as of yet. I have found several guides and now think my sql code is nearly correct but I'm still getting an error posted below.
System.Data.SqlClient.SqlException:
Only one expression can be specified
in the select list when the subquery
is not introduced with EXISTS
The error code says to use EXISTS but i have tried that instead of NOT IN and i still get an error.
My sql is posted below
SELECT TOP (#range) *
FROM client
WHERE clientId NOT IN
(SELECT TOP (#limit) *
FROM client
ORDER BY clientId)
ORDER BY clientId
The change you need to make to your code is
SELECT TOP (#range) *
FROM client
WHERE clientId NOT IN (SELECT TOP (#limit) clientId /*<-- NOT "*" here */
FROM client
ORDER BY clientId)
ORDER BY clientId
This can also be done by using row_number as below (which performs better depends on the different indexes available and how wide a covering index on the whole query is compared to a narrow one on just clientId.)
DECLARE #lowerlimit int
SET #lowerlimit = #range +#limit;
WITH cte As
(
SELECT TOP (#lowerlimit) * , ROW_NUMBER() OVER (ORDER BY clientId) AS RN
FROM client
ORDER BY clientId
)
SELECT * /*TODO: Your Actual column list*/
FROM cte
WHERE RN >= #limit
Another (similar, slower :) ) way
SELECT * FROM (
select rank() over (ORDER BY yourorder) as rank, *.X
from TableX X
) x2 WHERE rank between 5 and 10