Return a rowset and set a variable in an "IN" clause in SQL Server - sql

I want use the SQL Server IN operator and also set a variable to a column value. Is this possible?
My code is like this:
DECLARE #SubkindId as tinyint;
SELECT NAME FROM SampleTable001 WHERE
Id in (SELECT Id, #SubkindId = Subkind FROM SampleTable002)
ORDER BY Name;
My issue is: I want to set the #SubkindId variable in the inner select statement.

Can It Be Done?
In SQL Server you can't SELECT a result set and SET variables in the same statement (though you can in MySQL). Sorry. But there may be another way to get what you want. Unfortunately, what you want is not completely clear.
Assuming you want to do a SELECT and at the same time return another value into a variable, you have to handle the issue that your query can return multiple rows, so in that case, which one would you want to return into #SubkindId?
Now, I may have misunderstood, and instead of trying to pull the column value into the variable, you instead want to pull only the row where the SubkindId matches the value already in the variable (though you didn't show assigning a value to it first, so this seems less likely).
Please confirm which is the case and answer the above questions, and I can help you more.
In the meantime, I'll try to give you answers for both scenarios.
First, let me mention that I recommend against using the IN() syntax with a subquery returning a list of IDs. It is poor practice in my opinion because it usually demonstrates that the person doesn't really know how to JOIN properly, and as soon as the query gets a little complicated, not only that person but even the best professional SQL Server query writer can get lost (... WHERE x IN (SELECT ... WHERE y IN (SELECT ... WHERE z NOT IN (...))) which soon leads to a serious case of what!?!?!?!. Just use JOINs, and if required, semi-joins (introduced with an EXISTS clause).
Query and Return a Value
If what you really wanted was to get access to the values that the SELECT statement found while doing its join, it might look something like this:
DECLARE #KindsAndSubkinds TABLE (
Name varchar(100),
SubkindId tinyint
);
INSERT #KindsAndSubkinds
SELECT
T1.Name,
T2.SubkindId
FROM
dbo.SampleTable001 T1
INNER JOIN dbo.SampleTable002 T2
ON T1.Id = T2.Id
SELECT DISTINCT Name
FROM #KindsAndSubkinds
ORDER BY Name;
-- Now you can something with the `SubkindId`s in the #KindsAndSubkinds table variable.
Just Query
If you really were just trying to query rather than return a value, this is what I would recommend:
DECLARE #SubkindId as tinyint;
SET #SubkindId = 5;
SELECT
T1.Name
FROM
dbo.SampleTable001 T1
INNER JOIN dbo.SampleTable002 T2
ON T1.Id = T2.Id
WHERE
T2.Subkind = #SubkindId
ORDER BY
T1.Name;
If there are multiple rows in SampleTable002 but you don't want them in the result set, then:
SELECT
T1.Name
FROM
dbo.SampleTable001 T1
WHERE
EXISTS (
-- This semi-join requires at least one row to exist
-- but doesn't increase the row count
SELECT *
FROM dbo.SampleTable002 T2
WHERE
T1.Id = T2.Id
AND T2.Subkind = #SubkindId
)
ORDER BY
T1.Name;
I hope this helps.

Do it like this:
DECLARE #SubkindId as tinyint
SELECT [NAME]
FROM SampleTable001
WHERE Id in (SELECT Id
from SampleTable002
WHERE Subkind=#SubkindId)
order by [Name]
or by using JOIN
DECLARE #SubkindId as tinyint
SELECT [NAME]
FROM SampleTable001 a
INNER JOIN SampleTable002 b
ON a.id = b.id
WHERE b.Subkind=#SubkindId
order by [Name]

Related

SELECT query to return a row from a table with all values set to Null

I need to make a query but get the value in every field empty. Gordon Linoff give me the clue to this need here:
SQL Empty query results
which is:
select t.*
from (select 1 as val
) v left outer join
table t
on 1 = 0;
This query wors perfectly on PostgreSQL but gets an error when trying to execute it in Microsoft Access, it says that 1 = 0 expression is not admitted. How could it be fixed to work on microsoft access?
Regards,
If the table has a numeric primary key column whose values are non-negative then the following query will work in Access. The primary key field is [ID].
SELECT t2.*
FROM
myTable AS t2
RIGHT JOIN
(
SELECT TOP 1 (ID * -1) AS badID
FROM myTable AS t1
) AS rowStubs
ON t2.ID = rowStubs.badID
This was tested with Access 2010.
I am offering this answer here, even though you didn't think it worked in my edit to your original question. What is the problem?
select t.*
from (select max(col) as maxval from table as t
) as v left join
table as t
on v.val < t.col;
You can use the following query, but it would still need a little "manual coding".
EDITS:
Actually, you do not need the SWITCH function. Modified query below.
Removed the reference to Description column from one line. Still, you would need to use a Text column name (such as Description) in the last line of the query.
For example, the following query would work for the Months table:
select Months.*
from Months
RIGHT OUTER JOIN
(select "" as DummyColumn from Months) Blank_Data
ON Months.Description = Blank_Data.DummyColumn; --hardcoded Description column

SQL IN() operator with condition inside

I've got table with few numbers inside (or even empty): #states table (value int)
And I need to make SELECT from another table with WHERE clause by definite column.
This column's values must match one of #states numbers or if #states is empty then accept all values (like there is no WHERE condition for this column).
So I tried something like this:
select *
from dbo.tbl_docs docs
where
docs.doc_state in(iif(exists(select 1 from #states), (select value from #states), docs.doc_state))
Unfortunately iif() can't return subquery resulting dataset. I tried different variations with iif() and CASE but it wasn't successful. How to make this condition?
select *
from dbo.tbl_docs docs
where
(
(select count(*) from #states) > 0
AND
docs.doc_state in(select value from #states)
)
OR
(
(select count(*) from #states)=0
AND 1=1
)
Wouldn't a left join do?
declare #statesCount int;
select #statesCount = count(1) from #states;
select
docs.*
from dbo.tbl_docs docs
left join #states s on docs.doc_state = s.value
where s.value is not null or #statesCount = 0;
In general, whenever your query contains sub-queries, you should stop for five minutes, and think hard about whether you really need a sub-query at all.
And if you've got a server capable of doing that, in many cases it might be better to preprocess the input parameters first, or perhaps use constructs such as MS SQL's with.
select *
from dbo.tbl_docs docs
where exists (select 1 from #states where value = doc_state)
or not exists (select 1 from #state)

SQL Sybase Query Strange Behaviour

I've got 2 tables with exactly the same structure in the same Sybase database but they're separate tables.
This query works on one of the 2:
select * from table1 where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table1 As t1
where SECTOR = t1.SECTOR
AND
STATUS = 'QUOTA'
)
But for the second table I have to change it to this:
select * from table2 as tref where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table2 As t2
where tref.SECTOR = t2.SECTOR
AND
STATUS = 'QUOTA'
)
There's a restriction on where this will execute which means it needs to work like in the first query.
Does anyone have any ideas as to why the first might work as expected and the second wouldn't?
Since I am not yet allowed to comment, here as an answer to the question "does anyone...?":
No. I couldn't find anyone :)
This first query cannot work correctly, since it compares a column with itself (as long as the column names are all normal ASCII characters and not some similar looking UNICODE ones). Please give a proof that the result of this query is in every case the same as of query 2.
Also, the second query would normally be done like that: where SECTOR = tref.SECTOR...
You might be looking for something like this in query #1 :
select * from table1 t2 where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table1 As t1
where t2.SECTOR = t1.SECTOR
AND
t1.STATUS = 'QUOTA'
)
This explicitly specifies that the table in subquery is joining with the table in outer query ( co-related subquery ).
If this works, use the same idea in query #2

Create table from SQL query

This is one annoying issue and I can't figure out how to solve it. I'm Using Microsoft SQL Server 2008.
So I have two tables and I need to update both of them. They share a common key, say id. I want to update Table1 with some stuff and then update the Table2 rows which were respectively modified in Table1.
The issue is that I don't quite know which rows were modified, because I'm picking them randomly with ORDER BY NEWID() so I probably cannot use a JOIN on Table2 in any way. I am trying to save the necessary details which were modified in my query for Table1 and pass them to Table2
This is what I'm trying to do
CREATE TABLE IDS (id int not null, secondid int)
SELECT [Table1].[id], [Table1].[secondid]
INTO IDS
FROM
(
UPDATE [Table1]
SET [secondid]=100
FROM [Table1] t
WHERE t.[id] IN
(SELECT TOP 100 PERCENT t.[id] FROM [Table1]
WHERE (SOME_CONDITION)
ORDER BY NEWID()
)
)
UPDATE [Table2]
SET some_column=i.secondid
FROM [Table2] JOIN IDS i ON i.id = [Table2].[id]
But I get
Incorrect syntax near the keyword 'UPDATE'.
So the question is: how can I solve the syntax error or is it a better way to do this?
Note: the query enclosed between the parentheses of the first FROM worked well before this new requirement, so I doubt there's a problem in there. Or maybe?
EDIT: Changing the second UPDATE as skk suggested still leads to the same error (on exactly the below line which contains UPDATE):
UPDATE [Table2]
SET some_column=i.secondid
FROM [Task] JOIN IDS i on i.[id]=[Table2].[id]
WHERE i.id=some_value
Instead of creating a new table manually, SQL server has the OUTPUT clause to help with this
It's complaining because you aren't aliasing the derived table used in the first query, immediately preceding UPDATE [Table2].
If you add an alias, you'll get a different error:
A nested INSERT, UPDATE, DELETE, or MERGE statement must have an OUTPUT clause.
Which leads back to #Adam Wenger's answer.
Not sure I completely understand what you are trying to do, but the following sql will execute (after replacing SOME_CONDITION):
CREATE TABLE IDS (id int not null, secondid int)
UPDATE t SET [secondid] = 100
OUTPUT inserted.[id], inserted.[secondid] into [IDS]
FROM [Table1] t
WHERE t.[Id] IN
(
SELECT TOP 100 PERCENT t.[id] from [Table1]
WHERE (SOME_CONDITION)
ORDER BY NEWID()
)
UPDATE [Table2]
SET some_column = i.secondid
FROM [Table2] JOIN IDS i ON i.id = [Table2].[id]
The Update syntax is as follows
UPDATE TableName SET ColumnName = Value WHERE {Condition}
but you have used FROM keyword also in that.
EDIT:
You change the code like follows and try again
UPDATE [Table2] SET some_column=IDS.secondid WHERE IDS.[id] = [Table2].[id] and
IDS.id=some_value

Stored procedure: return multiple columns instead of multiple recordsets?

This is probably a really simple question, but I don't write stored procedures often and I'm a bit mystified...
After doing various stuff, the concluding bit of the SP ends by returning counts or sums from several different tables. The obvious approach is:
select SUM(ThisCol) as ThisResult from...
select SUM(ThatCol) as ThatResult from...
select count(DISTINCT OtherCol) as OtherResult from...
Of course, this creates multiple recordsets - one for each select plus one containing zero. This is a bit silly since each recordset contains exactly one value. I would much prefer to return a single recordset with multiple columns: ThisResult, ThatResult and OtherResult.
Is that possible?
You can use variables
DECLARE #thisResult INT
DECLARE #thatResult INT
DECLARE #otherResult INT
select #thisResult = SUM(ThisCol) as ThisResult from...
select #thatResult = SUM(ThatCol) as ThatResult from...
select #otherResult = count(OtherCol) as OtherResult from...
SELECT #thisResult AS 'thisResult', #thatResult AS 'thatResult', #otherResult AS 'otherResult'
SELECT T1.ThisResult, T2.ThatResult, T3.OtherResult
FROM (select SUM(ThisCol) as ThisResult from...) T1,
(select SUM(ThatCol) as ThatResult from...) T2,
(select count(DISTINCT OtherCol) as OtherResult from...) T3
Because each table contains only 1column & 1 value, you do a cross join of all 3 and put each value in a column in the result table.
If you're using SQL Server, you can select these quantities again as your last statement.
Select ThisResult, ThatResult, OtherResult
You don't have to specify a table