SQL Server select queries union all and limit - sql

I have a lot of problems to migrate queries from Mysql to SQL Server. I have this query that is a bit complicated but in mysql it works fine.
I have a select from a table union all to a select from another table not equals and a limit to paginate the results because the rows returned are a lot. When I tried to migrate to SQL Server, the selects with the union work fine. When I read how to implement a limit in T-SQL, in stackoverflow and another pages I learned how to do but when I try to apply it to my query it does not run and SQL Server returns an error.
The query without limit is the following (this query works well):
SELECT
'false' AS historico,
'' AS tabla,
a.nombre,
a.apellido1,
a.apellido2
FROM
persons a
WHERE
a.eliminado = 'N'
AND (idconv = 30)
UNION ALL
SELECT
'true' AS historico,
b.tabla,
b.nombre,
b.apellido1,
b.apellido2
FROM
persons_hist b
WHERE
b.eliminado = 'N'
AND (tabla = '1955')
ORDER BY
apellido1 ASC
but when I try to add "pagination" for example 10 rows starting in 0 this query returns me 18 rows 9 rows from the first table and 9 rows from the second table, but I have to paginate for example 10 rows from the union of 2 tables.
;WITH Results_CTE AS
(
select
ROW_NUMBER() OVER (ORDER BY apellido1 asc ) AS RowNum ,
'false' as historico,
'' as tabla,
a.nombre, a.apellido1, a.apellido2
from
persons a
where
a.eliminado = 'N' and (idconv = 30)
union all
select
ROW_NUMBER() OVER (ORDER BY apellido1 asc ) AS RowNum ,
'true' as historico,
b.tabla, b.nombre, b.apellido1, b.apellido2
from
persons_hist b
where
b.eliminado = 'N' and (tabla = '1997')
)
SELECT *
FROM Results_CTE
WHERE RowNum >= 0
AND RowNum < 0 + 10
Can somebody please help me?

one problem is that SQL SERVER row_number starts at 1 - you do not get a 0, so you have asked for 0 - 9 which will be 9 rows/
your other problem seems to be that row_number is calculated separately for each part of the UNION (which is logical for it to do so) - try calculating row number in a 2nd CTE
try
;WITH Results_CTE1 AS
(
select 'false' as historico,'' as tabla,a.nombre,a.apellido1,a.apellido2 from persons a where a.eliminado = 'N' and ( idconv = 30 )
union all
select 'true' as historico,b.tabla,b.nombre,b.apellido1,b.apellido2 from persons_hist b
where b.eliminado = 'N' and ( tabla = '1997' )
),
Results_CTE AS
(
SELECT *,ROW_NUMBER() OVER (ORDER BY apellido1 asc ) AS RowNum FROM Results_CTE1
)
SELECT *
FROM Results_CTE
WHERE RowNum BETWEEN 1 AND 10

You have 2 separate rownumbers in here. Try this:
WITH Results_CTE AS
(
'false' as historico,'' as tabla,a.nombre,a.apellido1,a.apellido2 from persons a where a.eliminado = 'N' and ( idconv = 30 )
union all
'true' as historico,b.tabla,b.nombre,b.apellido1,b.apellido2 from persons_hist b
where b.eliminado = 'N' and ( tabla = '1997' )
)
select *
from
(
select CTE1.*, row_number() over (order by apellido1 ) as RowNum
from Results_CTE
)
where RowNum <=10

Related

SQL Unique ID for union all - Sybase

Is it possible to generate a unique ID for the auxiliary table? I am retrieving data from several tables, but I do not know how to create a new ID for the results:
I would like to have an additional column with ID.
I tried to look for several methods, but nothing helped me.
I will be very grateful.
Greetings,
with ct as (
select *
INTO temp_table
from dba.view_NEW_Users_AreaCodes ur
join dba.view_NEW_Customers_SalesTowns ct on ct.CustSalesTerritoryTTID = ur.UserAreaCodeID
where ur.UserType = 'TT'
and ct.CustSalesTerritoryTTID <> 0
union all
select *
from dba.view_NEW_Users_AreaCodes ur
join dba.view_NEW_Customers_SalesTowns ct on ct.CustSalesTerritoryMTID = ur.UserAreaCodeID
where ur.UserType = 'MT'
and ct.CustSalesTerritoryMTID <> 0
union all
select *
from dba.view_NEW_Users_AreaCodes ur
join dba.view_NEW_Customers_SalesTowns ct on ct.CustSalesTerritoryHRCID = ur.UserAreaCodeID
where ur.UserType = 'HRC'
and ct.CustSalesTerritoryHRCID <> 0
union all
select *
from dba.view_NEW_Users_AreaCodes ur
join dba.view_NEW_Customers_SalesTowns ct on ct.CustSalesTerritoryDevID = ur.UserAreaCodeID
where ur.UserType = 'DEV'
and ct.CustSalesTerritoryDevID <> 0
)
select row_number() over (order by newid()) as DATA_ID,
ct.*
from ct;
You could use row_number():
with t as (
< your query here >
)
select row_number() over (order by newid()) as seqnum,
t.*
from t;
newid() is just an arbitrary value that randomizes the numbering. You can use a column there if you prefer a more canonical ordering.

How to use Dynamic Lag function to avoid joining a table to itself to retrieve date value

I'm currently writing code in SQL to add the column in red to the following table:
The logic is the following:
For every row:
if flag for this row =1 then use date of this row
if flag for this row =0 then find the latest row (based on date) on which flag was = 1 for the same party and return the date of that row. If no such row exists, return null
I've found a way to do this by joining the table to itself but I would like to avoid doing that as the size of the table is pretty massive.
What I have
select b.*, a.date,
from table a left join table b on a.party=b.party
where a.flag =1
Someone told me I could use the lag function, the partition over function and a case when to return the value I'm after but I haven't been able to figure it out.
Can someone help? Thank you so much!
try this
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0
select t.*,
max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
from #tab1 t
try this :->
select b.*, a.date, from table a left join table b on a.party=b.party where a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN ( SELECT date FROM ( SELECT TOP 1 row_number() OVER ( ORDER BY a.date DESC ) rs , a.date FROM a WHERE a.flag = 1 GROUP BY a.date) s ) END
use CROSS APPLY() to obtain the latest row with flag 1
SELECT *
FROM yourtable t
CROSS APPLY
(
SELECT TOP 1 x.Date as [Last flag on date]
FROM yourtable x
WHERE x.Party = t.Party
AND x.Flag = 1
ORDER BY x.Date desc
) d
Yes it can be done by joining table, if written properly.
#Sahi query is also good and simple.
Since you were asking for Dynamic LAG()
This query may or may not be very performant,but it certainly worth learning.
Test this with various sample data and tell me for which scenario it do not work.
So that I correct my script accordingly.
DECLARE #tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO #tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0;
WITH cte
AS (SELECT *,
Row_number()
OVER (
partition BY party
ORDER BY flag DESC, [date] DESC ) rn
FROM #tab1)
SELECT *,
CASE
WHEN flag = 1 THEN [date]
ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn
FROM cte a1
WHERE a1.party = a.party))
OVER (
ORDER BY party )
END
FROM cte a

Oracle Database Rownum Between

There are 25 records in this sql query
I want to get between 5 and 10. How can I do it ?
I use 11g
select
(
select count(*) as sayfasayisi
from konular t
where t.kategori is not null
) as sayfasayisi,
t.id,
t.uye,
t.baslik,t.mesaj,t.kategori,t.tarih,
t.edittarih,t.aktif,t.indirimpuani,t.altkategori,t.link,
nvl(
(select case when t.id = f.konuid and f.uye = 'test' then '1' else '0' end
from takipkonu f where t.id = f.konuid and f.uye = 'test'), '0') as takip
from konular t
where t.kategori is not null
You can use ROW_NUMBER() to assign a row number based on some ordering logic contained in your current query, e.g. a certain column. Then, retain only the 5th to 10th records:
select t.*
from
(
select
(
select count(*) as sayfasayisi
from konular t
where t.kategori is not null
) as sayfasayisi,
ROW_NUMBER() OVER (ORDER BY some_col) rn,
t.id,
t.uye,
...
) t
where t.rn between 5 and 10;

oracle query returns 4 duplicates of each row

I am running an Oracle query. It seems to work except that it returns 4 duplicates of each result. Here is the query:
Select * from (
Select a.*, rownum rnum From (
SELECT NEW_USER.*, NEW_EHS_QUIZ_COMPLETE.datetime
FROM NEW_USER, NEW_EHS_QUIZ_COMPLETE
WHERE EXISTS (
select *
from NEW_EHS_QUIZ_COMPLETE
where NEW_USER.id=NEW_EHS_QUIZ_COMPLETE.USER_ID
)
ORDER by last_name ASC
) a
where rownum <= #pgtop#
)
where rnum >= #pgbot#
Does anyone know why this isn't working properly?
You have a cross join here:
SELECT
NEW_USER.*,
NEW_EHS_QUIZ_COMPLETE.datetime
FROM NEW_USER, NEW_EHS_QUIZ_COMPLETE
WHERE EXISTS(
select * from NEW_EHS_QUIZ_COMPLETE
where NEW_USER.id=NEW_EHS_QUIZ_COMPLETE.USER_ID
)
You probably mean this:
SELECT
NEW_USER.*,
NEW_EHS_QUIZ_COMPLETE.datetime
FROM NEW_USER
INNER JOIN NEW_EHS_QUIZ_COMPLETE
ON NEW_USER.id = NEW_EHS_QUIZ_COMPLETE.USER_ID

SQL Server Top 1

In Microsoft SQL Server 2005 or above, I would like to get the first row, and if there is no matching row, then return a row with default values.
SELECT TOP 1 ID,Name
FROM TableName
UNION ALL
SELECT 0,''
ORDER BY ID DESC
This works, except that it returns two rows if there is data in the table, and 1 row if not.
I'd like it to always return 1 row.
I think it has something to do with EXISTS, but I'm not sure.
It would be something like:
SELECT TOP 1 * FROM Contact
WHERE EXISTS(select * from contact)
But if not EXISTS, then SELECT 0,''
What happens when the table is very full and you might want to specify which row of your top 1 to get, such as the first name? OMG Ponies' query will return the wrong answer in that case if you just change the ORDER BY clause. His query also costs about 8% more CPU than this modification (though it has equal reads)
SELECT TOP 1 *
FROM (
SELECT TOP 1 ID,Name
FROM TableName
ORDER BY Name
UNION ALL
SELECT 0,''
) X
ORDER BY ID DESC
The difference is that the inner query has a TOP 1 also, and which TOP 1 can be specified there (as shown).
Just for fun, this is another way to do it which performs very closely to the above query (-15ms to +30ms). While it's more complicated than necessary for such a simple query, it demonstrates a technique that I don't see other SQL folks using very often.
SELECT
ID = Coalesce(T.ID, 0),
Name = Coalesce(T.Name, '')
FROM
(SELECT 1) X (Num)
LEFT JOIN (
SELECT TOP 1 ID, Name
FROM TableName
ORDER BY ID DESC
) T ON 1 = 1 -- effective cross join but does not limit rows in the first table
Use:
SELECT TOP 1
x.id,
x.name
FROM (SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'') x
ORDER BY id DESC
Using a CTE equivalent:
WITH query AS (
SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'')
SELECT TOP 1
x.id,
x.name
FROM query x
ORDER BY x.id DESC
CREATE TABLE #sample(id INT, data VARCHAR(10))
SELECT TOP 1 id, data INTO #temp FROM #sample
IF ##ROWCOUNT = 0 INSERT INTO #temp VALUES (null, null)
SELECT * FROM #temp
put the top oustide of the UNION query
SELECT TOP 1 * FROM(
SELECT ID,Name
FROM TableName
UNION ALL
SELECT 0,''
) z
ORDER BY ID DESC
IF EXISTS ( SELECT TOP 1 ID, Name FROM TableName )
BEGIN
SELECT TOP 1 ID, Name FROM TableName
END
ELSE
BEGIN
--exists returned no rows
--send a default row
SELECT 0, ''
END