0

I have the two queries shown below:

declare @myTag1
select @myTag1= TagID
from tag.Tag
where TagName = 'MyTag1'

declare @myTag2
select @myTag2= TagID
from tag.Tag
where TagName = 'MyTag2'

How can I "merge" these queries into only one? I tried the below way:

SELECT CASE TagName
        WHEN 'MyTag1' THEN @MyTag1
        WHEN 'MyTag2' THEN @MyTag2
   END,
   @myValue = TagID
FROM   tag.Tag
WHERE  TagName IN ('MyTag1', 'MyTag2')

But it gives the following error.

Msg 141, Level 15, State 1, Line 9
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.

Any help would be much appreciated

  • 1
    As @DavidSpillett asked - why do you need this to be in a single query? It's not necessarily any more efficient. The reason could impact the best solution. – RDFozz Jan 9 '18 at 16:03
3

To fix the syntax of your second attempt:

SELECT @MyTag1 = CASE WHEN TagName= 'MyTag1' THEN TagID ELSE @MyTag1 END
     , @MyTag2 = CASE WHEN TagName= 'MyTag2' THEN TagID ELSE @MyTag2 END
FROM   tag.Tag
WHERE  TagName IN ('MyTag1', 'MyTag2')

(I'm not sure what @myValue was doing in there as it wasn't mentioned in the first example, so I've left that out.)

You may find this inefficient (it might scan, or at least do a partial scan) due to WHERE ... IN ... so watch the query plan. If that is the case then the sub-query option would be more efficient as you'll get two seeks instead.

When using the sub-query method if there might be many rows matching, add in TOP 1 so that the query engine will stop on finding the first value:

SELECT @myTag1 = (
            SELECT TOP 1
                   TagID
            FROM   tag.Tag
            WHERE  TagName = 'MyTag1'
            )
     , @myTag2 = (
            SELECT TOP 1
                   TagID
            FROM   tag.Tag
            WHERE  TagName = 'MyTag2'
            )

(it feels logical to assume that the query planner will be clever enough to know this is what you want, but I have seen it not do so in more complex examples and the explicit TOP 1 encourage a more efficient plan)

If you need many more properties pulling out than just the one or two, then you might find a PIVOT based solution more efficient (see Scott's answer for more detail on that). Again, check the resulting query plans for confirmation (and make sure you test with realistic data sizes/patterns or you may get a different plan and therefore performance profile in Dev/Test than in Production).

A question though: is there a reason why you need this to happen in a single statement? The sub-query version should be exactly equivalent to the two statement version and some may find the time simple statements slightly clearer to read. If you are concerned about data changing between the two statements, then wrap them in an explicit transaction (or the larger process if they are part of one) to try enforce consistency.

2

One solution would be to use sub-queries

set nocount on
Declare @TagTable table (TagID int, TagName varchar(30))
insert into @TagTable(TagID,TagName) values
(1,'MyTag1'),(2,'MyTag2')

DECLARE @myTag1 INT
DECLARE @myTag2 INT;

SELECT @myTag1 = (
        SELECT TagId
        FROM @TagTable
        WHERE TagName = 'MyTag1'
        )
    ,@myTag2 = (
        SELECT Tagid
        FROM @TagTable
        WHERE Tagname = 'MyTag2'
        )

PRINT @MyTag1
PRINT @MyTag2

Another option is to use PIVOT:

set nocount on
Declare @TagTable table (TagID int, TagName varchar(30))
insert into @TagTable(TagID,TagName) values
(1,'MyTag1'),(2,'MyTag2')

DECLARE @myTag1 INT
DECLARE @myTag2 INT;

;

WITH _cte
AS (
    SELECT Tagname
        ,TagID
    FROM @TagTable
    )
SELECT @MyTag1 = MyTag1
    ,@myTag2 = MyTag2
FROM _cte
PIVOT(min(TAgid) FOR TagName IN (
            MyTag1
            ,MyTag2
            )) AS pvt

PRINT @MyTag1
PRINT @MyTag2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.