I have a table named Department with 3 column: DepartmentID, DepartmentName, ParentID.
See SQL Fiddle for details
I want to order the results by ParentID and Generation. Like this:
╔═════════╦════════════════╦════════════╦══════════╗
║ ChildID ║ DepartmentName ║ Generation ║ ParentID ║
╠═════════╬════════════════╬════════════╬══════════╣
║ 1 ║ Manager ║ 0 ║ NULL ║
║ 6 ║ Sales ║ 1 ║ 1 ║
║ 7 ║ Fleet ║ 1 ║ 1 ║
║ 4 ║ Cargo ║ 2 ║ 7 ║
║ 5 ║ Transport ║ 2 ║ 7 ║
║ 2 ║ IT ║ 2 ║ 6 ║
║ 3 ║ Food ║ 2 ║ 6 ║
╚═════════╩════════════════╩════════════╩══════════╝
I tried different ORDER BYs but none worked.
My stored procedure:
WITH Hierarchy(ChildId, DeparmentName, Generation, ParentID)
AS
(
SELECT DepartmentID, DeparmentName, 0, ParentID
FROM Departments AS FirtGeneration
WHERE ParentID IS NULL
UNION ALL
SELECT NextGeneration.DepartmentID, NextGeneration.DeparmentName, Parent.Generation + 1, Parent.ChildId
FROM Departments AS NextGeneration
INNER JOIN Hierarchy AS Parent ON NextGeneration.ParentID = Parent.ChildId
)
SELECT * FROM Hierarchy
OPTION(MAXRECURSION 32767)
I use MS SQL Server 2005
Try storing the path to the top in the hierarchical query:
WITH Hierarchy(ChildId, DeparmentName, Generation, ParentID, Path) AS (
SELECT DepartmentID, DepartmentName, 0, ParentID,
RIGHT('000' + CAST(DepartmentID as VARCHAR(MAX)), 3) as Path
FROM Departments FirstGeneration
WHERE ParentID IS NULL
UNION ALL
SELECT NextGeneration.DepartmentID, NextGeneration.DeparmentName, Parent.Generation + 1, Parent.ChildId,
Path + '-->' + CAST(RIGHT('000' + CAST(NextGeneration.DepartmentID as VARCHAR(MAX)), 3)
FROM Departments NextGeneration INNER JOIN
Hierarchy Parent
ON NextGeneration.ParentID = Parent.ChildId
)
SELECT h.*
FROM Hierarchy h
ORDER BY path
OPTION(MAXRECURSION 32767);
Related
Table T:
ID | Name | Days
ID is the PK.
I do want to select * from T, order by ID descending, but on TOP to be those entries which have the ID between 1000 and 1004
select *
from T
order by Id descending // something like a *case*?
1004 - 1st / 1003 2nd / 1002 3rd / 1001 4th / 1000 5nd ... and then 6th should be the max Id, and after this all descending excepting the Ids between 1000 - 1004 which we already displayed on the TOP.
I would like to know also the linq statement.
SELECT *
FROM (VALUES (998), (999), (1000), (1001), (1002), (1003), (1004)) AS T(ID)
ORDER BY CASE
WHEN T.ID BETWEEN 1000 AND 1004 THEN 1
ELSE 2
END
, ID DESC;
Took sample data from Sick's answer.
How does this work?
It checks whether your ID is matching your criteria and assign it a
value of 1
Everything else will have 2
It will sort by this value first
Your IDs with matching criteria will ALWAYS come first
Then we sort leftovers by ID in DESC order
Output:
╔══════╗
║ ID ║
╠══════╣
║ 1004 ║
║ 1003 ║
║ 1002 ║
║ 1001 ║
║ 1000 ║
║ 999 ║
║ 998 ║
╚══════╝
I've made additional example, which generates 676.800 rows in our DB:
;WITH TestTable (ID)
AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.objects
CROSS JOIN sys.schemas
)
SELECT *
FROM TestTable AS T
ORDER BY CASE
WHEN T.ID BETWEEN 1000 AND 1004 THEN 1
ELSE 2
END
, ID DESC;
That's its result:
╔════════╗
║ ID ║
╠════════╣
║ 1004 ║
║ 1003 ║
║ 1002 ║
║ 1001 ║
║ 1000 ║
║ 676800 ║
║ 676799 ║
║ 676798 ║
║ 676797 ║
║ 676796 ║
║ 676795 ║
║ ... ║
║ 1006 ║
║ 1005 ║
║ 999 ║
║ 998 ║
║ ... ║
║ 1 ║
╚════════╝
Try this
select *
from T
order by case when ID between 1000 and 1004 then -100000 else id end,ID desc
Here -100000 is s random low value
Example :
SELECT *
FROM (VALUES (998),
(999),
(1000),
(1001),
(1002),
(1003),
(1004) ) tc (id)
ORDER BY CASE
WHEN ID BETWEEN 1000 AND 1004 THEN -100000
ELSE id
END,
ID DESC
SELECT column_name, column_name
FROM table_name
ORDER BY column_name ASC|DESC, column_name ASC|DESC;
I have this table:
╔═════╦════════╦════════════════╦══════════════════╗
║ drn ║ RecNum ║ Name ║ Value ║
╠═════╬════════╬════════════════╬══════════════════╣
║ 1 ║ 1 ║ ad1_pk ║ 1 ║
║ 2 ║ 1 ║ ad1_address1 ║ P.O. Box 5036 ║
║ 3 ║ 1 ║ ad1_address2 ║ NULL ║
║ 4 ║ 1 ║ ad1_address3 ║ NULL ║
║ 5 ║ 1 ║ ad1_ctyfk ║ 56 ║
║ 6 ║ 1 ║ ad1_postalcode ║ 80155-5036 ║
║ 7 ║ 1 ║ ad1_active ║ Y ║
║ 8 ║ 1 ║ ad1_irstat ║ A ║
║ 9 ║ 1 ║ ad1_irdata ║ NULL ║
║ 10 ║ 1 ║ ad1_at1fk ║ 1 ║
║ 1 ║ 2 ║ ad1_pk ║ 2 ║
║ 2 ║ 2 ║ ad1_address1 ║ 1871 S. Broadway ║
║ 3 ║ 2 ║ ad1_address2 ║ NULL ║
║ 4 ║ 2 ║ ad1_address3 ║ NULL ║
║ 5 ║ 2 ║ ad1_ctyfk ║ 1 ║
║ 6 ║ 2 ║ ad1_postalcode ║ 80210 ║
║ 7 ║ 2 ║ ad1_active ║ Y ║
║ 8 ║ 2 ║ ad1_irstat ║ A ║
║ 9 ║ 2 ║ ad1_irdata ║ NULL ║
║ 10 ║ 2 ║ ad1_at1fk ║ 1 ║
╚═════╩════════╩════════════════╩══════════════════╝
I am creating the pivot using this query:
declare #var nvarchar(max)
declare #sql nvarchar(max)
set #var = STUFF((select ',' + name from (select name from temp where recnum = 1)
as abc for xml path('')),1,1,'')
set #sql = 'select * from temp
pivot(max(value) for name in (' + #var + ')) as pvt'
exec sp_executesql #sql
This query works fine. I just read on google about SQL injection and came to know that my above query if added in stored procedure will have a SQL injection vulnerability.
So I modified the query to this SQL but I am getting error:
"Incorrect syntax near '#var".
declare #var nvarchar(max)
declare #sql nvarchar(max)
set #var = STUFF((select ',' + name from (select name from temp where recnum = 1)
as abc for xml path('')),1,1,'')
set #sql = 'select * from temp
pivot(max(value) for name in ( #var )) as pvt'
exec sp_executesql #sql,N'#var nvarchar(max)',#var
Can someone tell me what is wrong in my second query in which I tried to parameterize it?
I think the issue is, your column list in the outer SELECT statement needs to match the values in the IN statement, which it does not. You have select *, which is incorrect (echoing what #Bacon said). Without knowing exactly what you want, this is how your TSQL should look work:
select [1] as col1, [2] as col2, [3] as col3
from (
select Name, [Value]
from temp) p
pivot(
max([Value]) for Name in ( [1], [2], [3] )
) as pvt
;
You can read more about PIVOT here.
I am changing mysql queries to microsoft sql server 2008 queries, and in order to apply limit I need to select a ROW_NUMBER() that accumlates over each row and then apply a where condition WHERE RowNum >= 0 AND RowNum < 0 + 20 to select a certain limit with offset.
My issue however is that I can no longer select distinct because I have a column RowNum that is different with each row, here's my query:
USE mydatabase
GO
WITH Results_CTE
AS (
SELECT DISTINCT C.firstname
,C.lastname
,C.id AS clientid
,QC.category_name
,QR.id
,QR.cid
,QR.catid
,QR.rhid
,ROW_NUMBER() OVER (
ORDER BY QR.id DESC
) AS RowNum
FROM cms_question_report QR
,cms_clients C
,cms_questioncategory QC
WHERE C.id = QR.cid
AND QR.catid = '3'
AND QR.catid = QC.id
)
SELECT *
FROM Results_CTE
WHERE RowNum >= 0
AND RowNum < 0 + 20
And the results are:
╔═══════════╦══════════╦══════════╦═══════════════╦═══════╦═════╦═══════╦══════╦════════╗
║ firstname ║ lastname ║ clientid ║ category_name ║ id ║ cid ║ catid ║ rhid ║ RowNum ║
╠═══════════╬══════════╬══════════╬═══════════════╬═══════╬═════╬═══════╬══════╬════════╣
║ test ║ testing ║ 121 ║ Activity Log ║ 81499 ║ 121 ║ 3 ║ 0 ║ 19 ║
║ test ║ testing ║ 121 ║ Activity Log ║ 81498 ║ 121 ║ 3 ║ 0 ║ 20 ║
║ test ║ testing ║ 121 ║ Activity Log ║ 81497 ║ 121 ║ 3 ║ 0 ║ 21 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81496 ║ 120 ║ 3 ║ 0 ║ 22 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81495 ║ 120 ║ 3 ║ 0 ║ 23 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81494 ║ 120 ║ 3 ║ 0 ║ 24 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81493 ║ 120 ║ 3 ║ 0 ║ 25 ║
╚═══════════╩══════════╩══════════╩═══════════════╩═══════╩═════╩═══════╩══════╩════════╝
I took an example from the middle of the result. What I'm after is for example:
╔═══════════╦══════════╦══════════╦═══════════════╦═══════╦═════╦═══════╦══════╦════════╗
║ firstname ║ lastname ║ clientid ║ category_name ║ id ║ cid ║ catid ║ rhid ║ RowNum ║
╠═══════════╬══════════╬══════════╬═══════════════╬═══════╬═════╬═══════╬══════╬════════╣
║ test ║ testing ║ 121 ║ Activity Log ║ 81497 ║ 121 ║ 3 ║ 0 ║ 21 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81496 ║ 120 ║ 3 ║ 0 ║ 22 ║
╚═══════════╩══════════╩══════════╩═══════════════╩═══════╩═════╩═══════╩══════╩════════╝
Where I am trying to group the results by clientid. How do I achieve that?
USE ctarspla_mercycs
GO
WITH Results_CTE AS
(SELECT *, ROW_NUMBER() OVER (ORDER BY CLIENTID DESC) AS RowNum
FROM (SELECT DISTINCT
C.firstname,
C.lastname,
C.id as clientid,
QC.category_name,
QR.catid,
QR.rhid
FROM
cms_question_report QR,
cms_clients C,
cms_questioncategory QC
WHERE C.id=QR.cid
AND QR.catid=3
AND QR.catid=QC.id) t1)
SELECT * FROM Results_CTE
WHERE RowNum >= 0
AND RowNum < 0 + 20
I have a table containing a set of links that form a hierarchy. The big problem is that each link may be used several times (in different positions). I need to be able to distinguish between each "instance" of each node.
For example in the following data, link "D-G" will show up several times:
╔════════════╦════════╗
║ SOURCE ║ TARGET ║
╠════════════╬════════╣
║ A ║ B ║
║ A ║ C ║
║ B ║ D ║
║ B ║ E ║
║ B ║ F ║
║ C ║ D ║
║ C ║ E ║
║ C ║ F ║
║ D ║ G ║
║ E ║ D ║
║ F ║ D ║
╚════════════╩════════╝
I can build the hierarchy using a recursive CTE without any problems, but I want to give each row in the results a unique ID and link it to the parent node's unique ID.
My original idea was to assign a unique ID to each row using Row_Number() + Max(ID) up to this point and have the row inherit it's parents ID, but further reading and trial & error showed that this wont work :-(
Does anybody have an idea how to solve this problem (or at least give me a clue)?
The results should be something like this:
╔═════════════╦═════════════╦═══════════╦═══════════╗
║ SOURCE_DESC ║ TARGET_DESC ║ Source_ID ║ Target_ID ║
╠═════════════╬═════════════╬═══════════╬═══════════╣
║ A ║ B ║ 0 ║ 1 ║
║ A ║ C ║ 0 ║ 2 ║
║ B ║ D ║ 1 ║ 6 ║
║ B ║ E ║ 1 ║ 7 ║
║ B ║ F ║ 1 ║ 8 ║
║ C ║ D ║ 2 ║ 3 ║
║ C ║ E ║ 2 ║ 4 ║
║ C ║ F ║ 2 ║ 5 ║
║ D ║ G ║ 3 ║ 13 ║
║ E ║ D ║ 4 ║ 11 ║
║ F ║ D ║ 5 ║ 10 ║
║ D ║ G ║ 6 ║ 14 ║
║ E ║ D ║ 7 ║ 12 ║
║ F ║ D ║ 8 ║ 9 ║
║ D ║ G ║ 9 ║ 18 ║
║ D ║ G ║ 10 ║ 17 ║
║ D ║ G ║ 11 ║ 16 ║
║ D ║ G ║ 12 ║ 15 ║
╚═════════════╩═════════════╩═══════════╩═══════════╝
Here the "D-G" link shows up several times, but in each instance it has a different ID and a different parent ID!
I've managed to do it but I'm not happy with the way I did it. It doesn't seems very efficient (not important for this example but very important for much larger sets!)
WITH JUNK_DATA
AS (SELECT *,
ROW_NUMBER()
OVER (
ORDER BY SOURCE) RN
FROM LINKS),
RECUR
AS (SELECT T1.SOURCE,
T1.TARGET,
CAST('ROOT' AS VARCHAR(MAX)) NAME,
1 AS RAMA,
CAST(T1.RN AS VARCHAR(MAX)) + ',' AS FULL_RAMA
FROM JUNK_DATA T1
LEFT JOIN JUNK_DATA T2
ON T1.SOURCE = T2.TARGET
WHERE T2.TARGET IS NULL
UNION ALL
SELECT JUNK_DATA.SOURCE,
JUNK_DATA.TARGET,
CASE
WHEN RAMA = 1 THEN (SELECT [DESC]
FROM NAMES
WHERE ID = JUNK_DATA.SOURCE)
ELSE NAME
END NAME,
RAMA + 1 AS RAMA,
FULL_RAMA
+ CAST(JUNK_DATA.RN AS VARCHAR(MAX)) + ','
FROM (SELECT *
FROM JUNK_DATA)JUNK_DATA
INNER JOIN (SELECT *
FROM RECUR) RECUR
ON JUNK_DATA.SOURCE = RECUR.TARGET),
FINAL_DATA
AS (SELECT T2.[DESC] SOURCE_DESC,
T3.[DESC] TARGET_DESC,
RECUR.*,
ROW_NUMBER()
OVER (
ORDER BY RAMA) ID
FROM RECUR
INNER JOIN NAMES T2
ON RECUR.SOURCE = T2.ID
INNER JOIN NAMES T3
ON RECUR.TARGET = T3.ID)
SELECT T1.SOURCE_DESC,
T1.TARGET_DESC,
ISNULL(T2.ID, 0) AS SOURCE_ID,
T1.ID TARGET_ID
FROM FINAL_DATA T1
LEFT JOIN (SELECT ID,
FULL_RAMA
FROM FINAL_DATA)T2
ON LEFT(T1.FULL_RAMA, LEN(T1.FULL_RAMA) - CHARINDEX(',',
REVERSE(T1.FULL_RAMA), 2))
+ ',' = T2.FULL_RAMA
ORDER BY SOURCE_ID,
TARGET_ID
Check it out on SQL fiddle.
The query:
select Escuser,Eslevel from WF_UserConfiguration
is returning me the table bellow:
╔═════════════════════╗
║ Escuser Eslevel ║
╠═════════════════════╣
║ A000 1 ║
║ A010 4 ║
║ A021 3 ║
║ ABCD 1 ║
║ C067 3 ║
║ C099 1 ║
║ C252 2 ║
╚═════════════════════╝
My problem is I want to get the following output
╔═════════════════════════════╗
║ 1 2 3 4 ║
╠═════════════════════════════╣
║ A000 C252 A021 A010 ║
║ ABCD C067 ║
║ C099 ║
╚═════════════════════════════╝
The table headers 1, 2, 3 and 4 are EsLevel values of first query result.
How should I get the following result (I mean what query)?
The answer using pivot:
See live demo
select
[1],
[2],
[3],
[4]
from
(
select
Escuser,
Eslevel,
Row_number() over(partition by Eslevel order by escuser asc) as r
from WF_UserConfiguration
)src
pivot
(
max(escuser)
for Eslevel in
(
[1],[2],[3],[4]
)
)p