DISTINCT with PagedResults - sql

I am sure this will be answered somewhere...
Aim: Get DISTINCT DOCURL and additional columns
Tried:
1. Changing SELECT * FROM to SELECT DISTINCT DOCURL FROM which only yields the DOCURL column
2. Adding DISTINCT into the second select (as per example) but again I get all columns and rows.
Notes: Code is normally built dynamically so I've taken the print...
SELECT *
FROM
(
Select DISTINCT
isnull(d.DOCURL,'-') As DOCURL,
isnull(d.ID,'-') As ID,
isnull(d.UPRN,'-') As UPRN,
isnull(d.VFMDISCIPLINE,'-') As VFMDISCIPLINE,
isnull(d.VFMDISCIPLINEELEMENT,'-') As VFMDISCIPLINEELEMENT ,
isnull(d.SurveyDate,' ') As SurveyDate,
isnull(d.WorkOrder,'-') As WorkOrder,
ROW_NUMBER() OVER (ORDER BY DOCURL) AS ResultSetRowNumber
From TblData As D
WHERE 1 = 1
AND d.UPRN = '123XYZ'
AND (d.VFMDISCIPLINE = '1' OR d.VFMDISCIPLINE = '2' )
) As PagedResults
WHERE ResultSetRowNumber > 0 And ResultSetRowNumber <= 20

Assuming DOCURL is a unique column, the issue with the DISTINCT statement is that a new row number will be generated for each row in the sub query, therefore all rows will be considered different. You should apply distinct first and then get the row numbers.
Edit: I removed DISTINCT since your result set do not satisfy the criteria. Instead, I've added a partition inside the sub query, this way row numbers will start from 1 for each unique DOCURL and they're ordered by ID since I just assumed that's what you mean by first. Outer query reassigns row_numbers based on unique results from the sub query.
Select * From (
SELECT *, ROW_NUMBER() OVER (ORDER BY DOCURL) AS ResultSetRowNumber
FROM
(
Select
isnull(d.DOCURL,'-') As DOCURL,
isnull(d.ID,'-') As ID,
isnull(d.UPRN,'-') As UPRN,
isnull(d.VFMDISCIPLINE,'-') As VFMDISCIPLINE,
isnull(d.VFMDISCIPLINEELEMENT,'-') As VFMDISCIPLINEELEMENT ,
isnull(d.SurveyDate,' ') As SurveyDate,
isnull(d.WorkOrder,'-') As WorkOrder,
ROW_NUMBER() OVER (PARTITION BY d.DOCURL ORDER BY d.ID) As PART
From TblData As D
WHERE 1 = 1
AND d.UPRN = '123XYZ'
AND (d.VFMDISCIPLINE = '1' OR d.VFMDISCIPLINE = '2' )
) As t Where PART = 1
) As PagedResults
WHERE ResultSetRowNumber > 0 And ResultSetRowNumber <= 20

Related

Using subtraction of two queries in SELECT TOP query

I am struggling to prepare a query like this in SQL Server:
I have a table where I have a specific, constant value, let's say it's 15 (column defined as float)
In the same table I have one column where sometimes there is a value and sometimes it is a NULL value
So I would like to use SELECT TOP () query that would show me the number of records that is a result of subtraction of two queries:
SELECT
(SELECT DISTINCT Records
FROM Brand.Alle
WHERE HdNummer = '33')
-
(SELECT COUNT(AbrufNr)
FROM Brand.Alle
WHERE HdNummer = '33'
AND Transaction IS NOT NULL) AS DIFFERENCE
This query returns the result I want to have (let's say 13).
I would like to have selected top 13 records from a table I run a query against:
SELECT TOP (SELECT
(SELECT DISTINCT Records FROM Brand.Alle
WHERE HdNummer = '33')
-
(SELECT COUNT(AbrufNr) FROM Brand.Alle
WHERE HdNummer = '33' AND Transaction IS NOT NULL) AS DIFFERENCE) *
FROM Brand.Alle
WHERE HdNummer = '33' AND Transaction IS NULL
ORDER BY NEWID()
but it fails due to an error saying that I need to use an integer in select top statement. So the question is: how can I convert the value I receive as a result of subtraction two queries so I could use in in SELECT TOP?
I would highly appreciate any help.
Thank you in advance.
Number all your rows and only keep those with a number less or equal to the desired count.
with numbered as
(
select
alle.*,
row_number() over (order by newid()) as rn
from brand.alle
where hdnummer = 33
)
select *
from numbered
where rn <= ( <your count query here> );
Your count query can probably written shorter along the lines of:
select
count(distinct records) -
count(case when transaction is not null then abrufnr end) as cnt
from brand.alle
where hdnummer = 33;
And you can even combine the two with window functions in order to read from the table only once.
with numbered_and_counted as
(
select
alle.*,
count(distinct records) over () -
count(case when transaction is not null then abrufnr end) over () as cnt,
row_number() over (order by newid()) as rn
from brand.alle
where hdnummer = 33
)
select *
from numbered_and_counted
where rn <= cnt;

Remove all non contiguous records with identical fields

I got a table with some columns like
ID RecordID DateInserted
1 10 now + 1
2 10 now + 2
3 4 now + 3
4 10 now + 4
5 10 now + 5
I would like to remove all non contiguous duplicates of the RecordID Column when they are sorted by DateInserted
In my example I would like to remove record 4 and 5 because between 2 and 4 there is a record with different id.
Is there a way to do it with 1 query ?
You can use window functions. One method is to count the changes in value that occur up to each row and just take the rows with one change:
select t.*
from (select t.*,
sum(case when prev_recordid = recordid then 0 else 1 end) over (order by dateinserted) as grp_num
from (select t.*,
lag(recordid) over (order by dateinserted) as prev_recordid
from t
) t
) t
where grp_num = 1;
One way would be to "flag" all the rows where it is not the first time this RecordID appeared and the prior row contained a different RecordID. Then you just exclude any row beyond that point for that RecordID.
;WITH cte AS
(
SELECT ID, RecordID, DateInserted,
dr = DENSE_RANK() OVER (PARTITION BY RecordID ORDER BY DateInserted),
prior = COALESCE(LAG(RecordID,1) OVER (ORDER BY DateInserted), RecordID)
FROM dbo.table_name
),
FlaggedRows AS
(
SELECT RecordID, dr
FROM cte
WHERE dr > 1 AND prior <> RecordID
)
SELECT cte.ID, cte.RecordID, cte.DateInserted
FROM cte
LEFT OUTER JOIN FlaggedRows AS f
ON cte.RecordID = f.RecordID
WHERE cte.dr < COALESCE(f.dr, cte.dr + 1)
ORDER BY cte.DateInserted;
If you want to actually delete the rows from the source (remove will typically be inferred as removing from the result), then change the SELECT at the end to:
DELETE cte
FROM cte
INNER JOIN FlaggedRows f
ON cte.RecordID = f.RecordID
WHERE cte.dr >= f.dr;

cross join in query itself to match to see if it is not a last record

I am trying to get a record to match if its sortorder is not the last one in the complete recordset within a query itself
tried this query it gives me the min and count but what i am trying to get
WITH s AS (
SELECT MyGroup, Count(MyGroup) AS [Count],
RANK() OVER (ORDER BY Count(MyGroup)) AS [rasc],
RANK() OVER (ORDER BY Count(MyGroup) DESC) AS [rdesc]
FROM MyTable
GROUP BY (MyGroup)
)
SELECT
CASE
WHEN [rasc] = 1 THEN 'Min'
ELSE 'Max'
END AS 'Agg',
[MyGroup],
[Count]
FROM s
WHERE [rasc] = 1 OR [rdesc] = 1

Parameters for fetch first rows in query

I have the following query:
WITH lftno(counterrow) AS (
VALUES(select rownos
from test.table1
where year='2020' and usage='1')
)
UPDATE test.deltable
SET year=concat('31.12.','2012')
WHERE ID IN (
select res.id
from (
select res.id
from (
SELECT ROW_NUMBER() OVER (ORDER BY year ASC) AS delyear
, ID, year
from test.deltable
) res
where year(res.year)='2012'
fetch first integer(counterrow) rows only
)
The result of the with select is 10 so I want the fetch first line to use that 10 as the value for the rows to catch.
The final query is a lot longer but to show the problem this is easy for readablity.
I tried
'fetch first ' || integer(counterrow) || ' rows only'
or as part of the where clause
AND row_number() over() <= counterrow
but that didn't work either.
The point is that I can not resort them with an over part. I just need the lines as given by the counterrow.
Any ideas?
Thanks for you help.
You can't use row_number() in a WHERE clause. And, the FETCH clause requires constants. But, you can use the row_number() in a subquery and use the result in the outer query. If I understand correctly, you want:
WITH lftno(counterrow) AS (
VALUES(select rownos from test.table1 where year = '2020' and usage = '1')
)
select res.id
from (SELECT ROW_NUMBER() OVER (ORDER BY year ASC) AS delyear,
ID, year
from test.deltable
) res
where year(res.year) = '2012' and
delyear <= counterrow;

Total Row Count in sql query---sql server 2008

My query is as follows
BEGIN
WITH MyCTE
AS (
SELECT T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,D.musicFileName
,T.ReleaseDate AS ReleasedDate
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
,ROW_NUMBER() OVER (
PARTITION BY D.MusicVideoID ORDER BY D.mVideoID
) AS row_num
FROM dbo.Music_Video T
JOIN dbo.Music_Video_Details D ON T.MusicVideoID = D.MusicVideoID
WHERE T.PortalID = #PortalID
AND T.CultureCode = #CultureCode
AND T.ComingSoon <> 1
GROUP BY T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,T.ReleaseDate
,D.musicFileName
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
)
SELECT a.mVideoID
,a.MusicVideoID
,a.musicFileName
,a.MusicAlbumTitle
,a.ReleasedDate
,a.row_num
,a.CoverImg
,a.ExternalLink
,a.musicTitle
,a.MusicLength
FROM MyCTE a
WHERE row_num = 1
ORDER BY MusicVideoID DESC
END
I need to achieve total row count from last select statement.
which mean total row count that is being selected.
or any idea that might be use in this condition
How can i do this ..
Please add COUNT(*) OVER() in your select, which returns total rows selected as a new column.
Ex:
SELECT
*,
COUNT(*) OVER() AS [Total_Rows]
FROM YourTable
Just to be clear, you need to add the count to the CTE, not the outer query. The outer select is returning only one row, so the count would always be one.
The CTE should start:
WITH MyCTE
AS (
SELECT T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,D.musicFileName
,T.ReleaseDate AS ReleasedDate
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
,ROW_NUMBER() OVER (
PARTITION BY D.MusicVideoID ORDER BY D.mVideoID
) AS row_num,
COUNT(*) over () as total_count