Sql inner query issue - sql

I have a table tbl_test:
create table tbl_test (
tabid int identity
)
with the values:
Insert into tbl_test values 1 union 2 union 3 .... union 1000
Query:
select MAX(b.tabid) from
(
select top 100 * from tbl_test
) as b
I expect this query to return 100 but instead it returns 1000.

select top 100 * from tbl_test
There is no explicit order on the inner statement, so there is no guarentee in which order the rows are read. If you order it by tabid ASC you should see the expected 100.

You're not including an order by clause in your subquery (which is allowed in conjunction with TOP), so there's no telling what records will come back. 1000 is obviously being included in the data returned from the subquery, which means it will be returned by MAX.

Related

SQL Using TOP n with UNION, but only want results of second query if first does not have enough records

I am trying to write a sql statement that works something like a store. I have two queries and I want n records from the first query, but if there is less than n, I want the rest from the second.
I tried using TOP n and UNION
SELECT TOP 20 FROM (
(SELECT * FROM t1)
UNION
(SELECT * FROM t2))
but the results are from both tables regardless of how many are in t1. Basically, I want the first query to have precedence. If 5 records exist there and I want them and I want the rest from t2.
Add a column that identifies the query, so the first one have precedence.
SELECT TOP 20 *
FROM ((SELECT 1 as query, * FROM t1)
UNION
(SELECT 2 as query, * FROM t2))
ORDER BY query
you can use a CTE to place a sort order on the two tables and then use that in an order by clause
declare #foo1 table(
bar INT
)
insert into #foo1
values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
--,(11),(12),(13),(14),(15),(16),(17),(18),(19),(20)
declare #foo2 table(
bar INT
)
insert into #foo2
values (101),(102),(103),(104),(105),(106),(107),(108),(109),(110),(111),(112),(113),(114),(115),(116),(117),(118),(119),(120)
;with base_data as (
select
0 as sort,
f1.bar
FROM #foo1 f1
UNION
SELECT
1 as sort,
f2.bar
FROM #foo2 f2
)
select top 20 bar
from base_data
order by sort, bar

Is it possible to use a subquery more than once?

I was wondering if it was possible to use a subquery in SQL more than once.
For example:
with subQuery as (
select id from someTable1
)
update someTable2
set someValue = 1
where id in (select * from subQuery)
select * from someTable2
where id in (select * from subQuery)
...
As of right now, SQL throws an error on the (select * from subQuery) in the select * someTable2 clause saying "Invalid Object Name subQuery". So is there a way to use subQuery more than once without having to add a table or run the query multiple times changing out the first statement?
A CTE is in scope only for a single query, but a query can both UPDATE and OUTPUT data. eg
with subQuery as (
select id from someTable1
)
update someTable2
set someValue = 1
output inserted.*
where id in (select * from subQuery)

Get a defined row instead of empty result set: SQL Server

I need a query that return rows even if they have no matching data in table. I know that an empty result set will be returned, but as my project necessity, I need to get a row in result set. It is acceptable though that the values are null. Below is my query:
select Demographic_Id, Total from school.Demographic_Profile where Demographic_Id=2
There is no data with Demographic_Id equal to 2. Still I need to get a result like this:
Demographic_Id | Total
2 | NULL
Any suggestions would help a lot!
If you would get exactly one row or zero rows, then a trick is to use aggregation:
select 2 as Demographic_Id, max(Total) as Total
from school.Demographic_Profile
where Demographic_Id = 2;
You could also use an outer join
select v.did As Demographic_Id,
Total
from (values(2)) v(did)
LEFT JOIN school.Demographic_Profile ON Demographic_Id=v.did
You might use a CTE. The CTE will create a derived table. The UNION ALL will append one row, but only in case the query did not return any rows. Otherwise the query will return just as expected:
WITH CTE AS
(
SELECT object_id
,name
FROM sys.objects
WHERE name='non-existent'
)
SELECT * FROM CTE
UNION ALL
SELECT 2,NULL WHERE (SELECT COUNT(*) FROM CTE)=0
For your case try this:
DECLARE #id INT=2
WITH CTE AS
(
select Demographic_Id, Total
from school.Demographic_Profile
where Demographic_Id=#id
)
SELECT * FROM CTE
UNION ALL
SELECT #id,NULL WHERE (SELECT COUNT(*) FROM CTE)=0
select Demographic_Id, Total from
(SELECT 1 as did
UNION ALL
SELECT 2 as did
UNION ALL
SELECT 3 as did) as innerQuery
left outer join school.Demographic_Profile on did = Demographic_Id

SELECT TOP ... FROM UNION

What is the best way to SELECT TOP N records from UNION of 2 queries?
I can't do
SELECT TOP N ... FROM
(SELECT ... FROM Table1
UNION
SELECT ... FROM Table2)
because both queries return huge results I need every bit of optimization possible and would like to avoid returning everything. For the same reason I cannot insert results into #TEMP table first either.
I can't use SET ROWCOUNT N either because I may need to group results and this command will limit number of grouped rows, and not underlying row selections.
Any other ideas? Thanks!
Use the Top keyword for inner queries also:
SELECT TOP N ... FROM
(SELECT TOP N... FROM Table1
UNION
SELECT TOP N... FROM Table2) as result
You could try the following. It uses a CTE which would give you the results of both queries first and then you would select your TOP N from the CTE.
WITH table_cte (
(
[col1],
[col2],
...
)
AS
(
SELECT *
FROM table1
UNION ALL
SELECT *
FROM table2
)
SELECT TOP 1000 * FROM table_cte

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