SQL order by creation time ASC - sql

I have this query:
SELECT
p.[TerminalId],
Keys = JSON_QUERY('[' + string_agg(json_query('{"Point":"' + p.Location.STAsText() + '","CreatedDateTime":"' + cast(p.CreatedDateTime as nvarchar(20)) + '"}'),',') + ']')
FROM
(SELECT
geography::STGeomFromText(Location.STAsText(), 4326) as Location,
[CreatedDateTime],
[TerminalId],
ROW_NUMBER() OVER (ORDER BY [CreatedDateTime] ASC) AS RowNum
FROM
[Magicar_Route].[dbo].[PacketLocations]) AS p
GROUP BY
p.[TerminalId]
I want p.Location sorted by CreatedDateTime asc in Keys JSON column but after query Location not sorted ASC?
How could I sort my location according CreatedDateTime ASC?
I changed my query to this:
WITH NewScores AS
(
SELECT
geography::STGeomFromText(Location.STAsText(), 4326) AS Location,
[CreatedDateTime],
[TerminalId]
FROM
[Magicar_Route].[dbo].[PacketLocations]
ORDER BY
[CreatedDateTime] ASC
)
SELECT
[TerminalId],
Keys = JSON_QUERY('['+ string_agg(json_query('{"Point":"' + Location.STAsText() + '","CreatedDateTime":"' + cast(CreatedDateTime as nvarchar(20)) + '"}'),',') + ']')
FROM
NewScores
But unfortunately I got this error:
Msg 1033, Level 15, State 1, Line 100
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.

Instead of putting the order by inside the CTE, put it for the query below
WITH NewScores AS
(
SELECT
geography::STGeomFromText(Location.STAsText(), 4326) AS Location,
[CreatedDateTime],
[TerminalId]
FROM
[Magicar_Route].[dbo].[PacketLocations]
)
SELECT
[TerminalId],
Keys = JSON_QUERY('['+ string_agg(json_query('{"Point":"' + Location.STAsText() + '","CreatedDateTime":"' + cast(CreatedDateTime as nvarchar(20)) + '"}'),',') + ']')
FROM
NewScores
ORDER BY
[CreatedDateTime] ASC

Related

STUFF only unique values along with sorting another column

I want to combine values with comma-separated. For that used stuff.
But my data has duplicate values, and I just need unique items from that.
Here is a query that I'm using.
SELECT STUFF
(
RTRIM
(
( SELECT N', ' + CAST(column1Name AS varchar(MAX))
FROM dbo.tableName
ORDER BY column2Name
FOR XML PATH (N'')
)
)
, 1, 2, N'')
I tried SELECT DISTINCT within STFF, but that requires a column that used for sorting within SELECT clause, I am using STUFF so I can't use that column in SELECT clause.
SELECT STUFF
(
RTRIM
(
( SELECT DISTINCT N', ' + CAST(column1Name AS varchar(MAX))
FROM dbo.tableName
ORDER BY column2Name
FOR XML PATH (N'')
)
)
, 1, 2, N'')
I also tried to use sub-query to do sorting and use distinct outside, but that also gave a compile error.
SELECT STUFF
(
RTRIM
(
( SELECT DISTINCT N', ' + CAST(column1Name AS varchar(MAX))
FROM
(
SELECT column1Name
FROM dbo.tableName
ORDER BY column2Name
) tableAlias
FOR XML PATH (N'')
)
)
, 1, 2, N'')
I also tried GROUP BY, which also forces me to add column2Name in the SELECT clause.
SELECT STUFF
(
RTRIM
(
( SELECT N', ' + CAST(column1Name AS varchar(MAX))
FROM dbo.tableName
GROUP BY column1Name
ORDER BY column2Name
FOR XML PATH (N'')
)
)
, 1, 2, N'')
Is there any way to stuff unique values along with sorting based on a different column?
You can still use the GROUP BY method. The only thing is when you GROUP BY column1Name, there might be multiple value of column2Name, so you need to use aggregate on it, example MIN(column2Name)
SELECT STUFF
(
RTRIM
(
( SELECT N', ' + CAST(column1Name AS varchar(MAX))
FROM dbo.tableName
GROUP BY column1Name
ORDER BY MIN(column2Name)
FOR XML PATH (N'')
)
)
, 1, 2, N'')

SQL Pivot - take a changing date from column and make it a row header

I have a basic query that looks like this.
SELECT Database_Name,
FilingDate,
SUM(ISNULL([column1], 0) + ISNULL(column2], 0) +
ISNULL([column3], 0) + ISNULL([column4], 0)) AS Total
FROM SomeTable(NOLOCK)
GROUP BY Database_Name,
FilingDate
ORDER BY Database_Name,
FilingDate DESC
This query outputs results that look like this.
I would like to take the dates returned in the FilingDate column and use them as new column headers with the totals for each database and date being used as the row content. The end result should look like this:
My research suggests that a pivot is the best option but I'm struggling to find the right way to execute it as my dates change each day Any assistance would be appreciated.
If this is MS SQL, you can use a dynamic pivot table. Here is a solution using your query (should work, but I don't have the base data to test it).
SELECT Database_Name,
FilingDate,
SUM( ISNULL(column1 ,0) +
ISNULL(column2],0) +
ISNULL([column3],0) +
ISNULL([column4],0)
) AS Total
INTO #T1
FROM SomeTable(NOLOCK)
GROUP BY Database_Name,
FilingDate
DECLARE #PivotColumnHeaders varchar(MAX)
SELECT #PivotColumnHeaders =
COALESCE(
#PivotColumnHeaders + ',[' + CAST(UC.FilingDate AS NVARCHAR(10)) + ']',
'[' + CAST(UC.FilingDate AS NVARCHAR(10)) + ']'
)
FROM (SELECT FilingDate FROM #T1 GROUP BY FilingDate) UC
DECLARE #PQuery varchar(MAX) = '
SELECT * FROM (SELECT Database_Name, FilingDate, Total FROM #T1 T0) T1
PIVOT (SUM([Total]) FOR FilingDate IN (' + #PivotColumnHeaders + ') ) AS P'
EXECUTE (#PQuery)
DROP TABLE #T1

Query Filter based on condition

I have this query (SQL Server 2019) and I actually wanted to add a filter to it to show only items where IssueStatusID = 1 (This column is based on int Data Type)
Can anyone help with this or point me in the right direction?
SELECT ID,
STRING_AGG(TRY_CONVERT(varchar, Issue#, 101) + ': ' + Notes + CHAR(13) + CHAR(10) + CHAR(13), CHAR(10)) WITHIN GROUP (ORDER BY Issue# DESC) AS IssueNotes
FROM (SELECT DISTINCT
ac4.ID,
nd.Notes,
nd.Issue#,
nd.IssueStatusID
FROM dbo.IssueTracking AS nd
INNER JOIN dbo.StatusUpdates AS ac4 ON ac4.ID = nd.ReleaseTrackerID) AS vNotes
GROUP BY ID;
Add the WHERE clause as shown below. The WHERE clause limits the data being returned.
SELECT ID,
STRING_AGG(TRY_CONVERT(varchar, Issue#, 101) + ': ' + Notes + CHAR(13) + CHAR(10) + CHAR(13), CHAR(10)) WITHIN GROUP (ORDER BY Issue# DESC) AS IssueNotes
FROM (SELECT DISTINCT
ac4.ID,
nd.Notes,
nd.Issue#,
nd.IssueStatusID
FROM dbo.IssueTracking AS nd
INNER JOIN dbo.StatusUpdates AS ac4 ON ac4.ID = nd.ReleaseTrackerID
WHERE nd.IssueStatusID = 1
) AS vNotes
GROUP BY ID;

SQL Return subquery 'Total Records' to outer query

This one has me a little stumped, I'm trying to get the total count in my top (root) node XML from this SQL query:
SELECT COUNT(*) OVER() as '#totalCount', (
SELECT COUNT(*) OVER() as totalCount, [Title], [Year], [Type], [Poster]
FROM movies As result where CONTAINS(Title, #Title) Order by [Weight] DESC
OFFSET ((#PageNumber - 1) * #RowspPage) ROWS
FETCH NEXT #RowspPage ROWS ONLY
FOR XML AUTO, type
)
FOR XML PATH('root')
Obviously the COUNT(*) OVER() is only returning "1" because it's being executed at the top level and not within the subquery. But I only want to display it once in the root node and not repeat per each result.
Any help would be greatly appreciated.
EDIT: Here a working example with common data to walk along:
;with myCTE as
(
select *
from sys.objects
)
select (select count(*) from myCTE) as [#Counter]
,(
SELECT myCTE.object_id AS id
,mycte.name AS name
from myCTE
for xml path('object'),TYPE
)
for xml path('test')
You might try to shift your query into a CTE and put it to something like this:
;WITH MyQueryAsCTE AS
(
SELECT [Title], [Year], [Type], [Poster]
FROM movies As result where CONTAINS(Title, #Title) Order by [Weight] DESC
OFFSET ((#PageNumber - 1) * #RowspPage) ROWS
FETCH NEXT #RowspPage ROWS ONLY
)
SELECT (SELECT Count(*) FROM MyQueryAsCTE) as '#totalFound'
,[Title] AS [Movie/Title]
,[Year] AS [Movie/Year]
,[Type] AS [Movie/Type]
,[Poster] AS [Movie/Poster]
FROM MyQueryAsCTE
FOR XML PATH('root')
Fun with strings... This is a total hack, but it works:
DECLARE #totalCount AS INT
DECLARE #result varchar(MAX)
SELECT #totalCount = COUNT(*) OVER(), #result = COALESCE(#result + '', '') + '<result title="' + [Title] + '" year="' + [Year] + '" type="' + [Type] + '"/>'
FROM Movies where CONTAINS(Title, '#Title') Order by [Weight] DESC
OFFSET ((#PageNumber - 1) * #RowspPage) ROWS
FETCH NEXT #RowspPage ROWS ONLY
SELECT '<root totalCount="' + CAST(#totalCount AS VARCHAR) + '">' + #result + '</root>'
Output:
Seems to have a faster/more efficient execution plan as the calculation is only made once and no additional queries to any tables are required.

Select values from multiple rows from 1 table as 1 record

I'm struggling to even explain what I need to do so please be patient with me.
I have the following table and rows in it:
TBNAME: Distances
Track, Person, Date, Distance
TRACK1, P1, 1/1/2014, 15
TRACK2, P1, 13/1/2014, 12
TRACK1, P1, 20/2/2014, 10
TRACK2, P1, 15/1/2014, 9
TRACK1, P2, 2/1/2014, 11
TRACK2, P2, 14/1/2014, 13
TRACK1, P2, 21/2/2014, 8
TRACK2, P2, 16/1/2014, 6
What I would, ideally, like to see as a result is something like this:
P1, TRACK1, 20/2/2014, 10, TRACK2, 15/1/2014, 9
P2, TRACK1, 21/2/2014, 8, TRACK2, 16/1/2014, 6
Or, in other words, for each person, the most recent date and distance for that date for each track in one row.
Hope someone can understand this and offer a solution too :)
Cheers,
Pierre
Try this:
SELECT T1.Person, T1.Track, MAX(T1.Date), MIN(T1.Distance),
T2.Track, MAX(T2.Date), MIN(T2.Distance)
FROM Distances AS T1 INNER JOIN
Distances AS T2 ON T1.Person = T2.Person
WHERE T1.Track <> T2.Track AND T1.Track = 'Track1'
GROUP BY T1.Track, T1.Person, T2.Track
The output result of the query is showing exactly the same of your expected result.
Try combining the table by itself and connecting them with the common column.
In your case you want Person.
Select t1.Person,
t1.Tract,
t1.Date,
t1.Distance,
t2.Tract,
t2.date,
t2.Distance
From table_name t1, table_name t2
WHERE t1.Person = t2.Person;
Try this:
SELECT DISTINCT ON ("Person", "Track") *
FROM "Table"
ORDER BY "Person", "Date" DESC NULLS LAST;
Here is a query to get the records needed. First get the maximum date per track and person. Then join with the table to get the complete record.
If you know beforehand which tracks you will get, you can use a pivot query for this. As I've never done this, I ask you to look this up yourself. However, as mentioned in my comment to your request, I would use a programming language (C#, Java, PHP or whatever) to care about that.
select d.track, d.person, d.date, d.distance
from
(
select track, person, max(distances.date) as `date`
from distances
group by track, person
) lastd
inner join distances d on d.track = lastd.track and d.person = lastd.person and d.date = lastd.date
order by d.track, d.person;
BTW: date is a reserved keyword. I would not recommend to use it for a column name. Whenever you use it without a qualifier you will have to use those strange quotes.
Look for ROW_NUMBER() and OVER PARITION BY.
Idea is something like (I did not try to run this query):
;WITH
data AS
(
SELECT
*,
-- returns number for each pair of person and track starting from most recent date
--Code enhanced at here
row_number() over (partition BY person, track order by dte DESC) nr
FROM distances
)
SELECT
*
FROM
data
WHERE
nr = 1 -- we want just the most recent one
ORDER BY
person, -- "group by" person
track ;
It's still doesn't support showing one row for each person...
I don't think you can do it with SQL (because of unknown number of tracks).
There is PIVOT/UNPIVOT, but I don't think it fits here.
WITH CTE AS
(
Select P1.Track,P1.Person,ROW_NUMBER() OVER (Partition by Person,Track Order by Date
Desc) AS RN1
,Date,Distance
from Distances P1
)Select T.Person,T.Track1,T.T1Date
,T.T1Distance,T.Track2,T.T2Date,T.T2Distance
From (
Select C1.Person,C1.Track AS 'Track1',C1.Date AS 'T1Date',
C1.Distance 'T1Distance',
C2.Track AS 'Track2',C2.Date As 'T2Date',C2.Distance 'T2Distance',
ROW_NUMBER() OVER (Partition BY C1.Person Order by C1.Date Desc) RNX
from
CTE C1
JOIN
CTE C2 ON C1.RN1=1 AND C2.RN1=1
AND C1.Person=C2.Person
AND C1.Track<>C2.Track
)t Where t.RNX=1
you may also use dynamic query to achieve your expected result :)
DECLARE #nCount INT
DECLARE #nStart INT
DECLARE #Query NVARCHAR(MAX) =' '
DECLARE #sPerson NVARCHAR(MAX)
DECLARE #sTrack NVARCHAR(MAX)
SET #nCount = (SELECT COUNT(DISTINCT(person)) FROM DISTANCES)
SET #nStart = 1
WHILE #nStart <= #nCount
BEGIN
SET #sPerson = (SELECT PERSON FROM (
SELECT PERSON, ROW_NUMBER() OVER (ORDER BY PERSON) RN FROM (
SELECT DISTINCT(PERSON) FROM DISTANCES
) T1
) T2 WHERE RN = #nStart
)
SET #Query = #Query + '
SELECT '''+#sPerson+''' + '','' + STUFF( '','' +(
SELECT TRACK + '', '' + DATE + '', '' + DISTANCE FROM (
SELECT TRACK, DATE,DISTANCE,
ROW_NUMBER() OVER (PARTITION BY TRACK ORDER BY DATE DESC) RN FROM (
SELECT TRACK,date,DISTANCE FROM DISTANCES WHERE PERSON = '''+#sPerson+'''
) T1
) T2
WHERE RN = 1 FOR XML PATH('''')
),1,1,''''
)
'
IF(#nStart != #nCount)
SET #Query = #Query + ' UNION ALL '
SET #nStart = #nStart + 1
END
EXEC SP_EXECUTESQL #Query
To have a general query it need to be dynamic
DECLARE #query AS NVARCHAR(MAX)
DECLARE #pivotCols AS NVARCHAR(MAX)
DECLARE #cols AS NVARCHAR(MAX)
SELECT #pivotCols = STUFF((SELECT DISTINCT ',' + QUOTENAME([Track])
FROM Distances
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') , 1, 1, '')
;WITH T AS (
SELECT Track
, _ID = CAST(Row_Number() OVER (ORDER BY Track) AS VARCHAR)
FROM Distances
GROUP BY Track
)
SELECT #Cols = STUFF((
SELECT ', Track_' + _ID + ' = ''' + Track + ''''
+ ', LastRun_' + _ID + ' = ' + QUOTENAME([Track])
+ ', Distance_' + _ID + '
= SUM(CASE WHEN d.Date = ' + QUOTENAME([Track]) + '
AND d.Track = ''' + Track + '''
THEN d.Distance ELSE NULL END)'
FROM T FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') , 1, 1, '')
SELECT #query = '
With LR AS (
SELECT Person, ' + #pivotCols + '
FROM (SELECT Track, Person, [Date] FROM Distances) d
PIVOT (MAX([Date]) FOR Track IN (' + #pivotCols + ')) pvt
)
SELECT d.Person, ' + #Cols + '
FROM Distances d
INNER JOIN LR ON d.Person = LR.Person AND d.Date IN (' + #pivotCols + ')
GROUP BY d.Person, ' + #pivotCols + ''
execute(#query);
SQLFiddle demo
The first query generate the list of field for the PIVOT.
The second one generate the fields for the compound query.
The PIVOT is used to get, for every person, the last run on every track, that is than joined back to the base data to get the distance