question

Clint avatar image
Clint asked

dynamic sql select statement

I'll try to explain this one with as little code as possible.

I have created a table that defines certain tags and thier properties

If I write code like ( this is a query to the table i created)

Select Tag 
  From Tags 
  where shift = 'Am'

I get a list of 200 or so tags

To get the values of that have values I want to see I write

select h.tag, max(value)
from v_history as h 
where tag in ('Tagname1')
or tagn in ('tagname2')

THIS WORKS FINE.... here is where I am running into trouble

If I define a CTE

with am as 
(
Select Tag as am_tag
  From Tags 
  where shift = 'Am'
)

Then try to run the query

select h.tag, max(value)
from v_history as h 
where h.tag in am_tag

I get an error that says i must have at least one tag for history queries.

I think what i need to do is have a query that writes out the tagname (maybe runing one line at a time??) any ideas ?

dynamicloop
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Oleg avatar image
Oleg answered

Clint,

The statement

select h.tag, max(value) from v_history as h where tag in ('Tagname1') or tag in ('tagname2')

does not appear to be correct. First, there is no need to write in ('Tagname1') or tag in ('tagname2'), this part should be restated like this

tag in ('Tagname1', 'Tagname2')

Second, if your v_history has one or more records per tag then you should group by the tag field in order to see the max(value). In other words, your statement should look like this:

select h.tag, max(value) from v_history as h 
where tag in ('Tagname1', 'Tagname2')
group by h.tag

Finally, if you would like to get the list of tags from AM shift along withh their max(value) from v-history table then you should join those 2 tables by tag. There is no need to write cte for it, but if you need one then your statement should look like this (I follow your naming conventions):

with am (am_tag) as 
(select Tag as am_tag From Tags where shift = 'Am')
select h.tag, max(h.value) 
from v_history as h inner join am
on am.am_tag = h.Tag
group by h.tag;

If your history table has has zero or more records per tag rather than has one or more per tag and you would like to include the tags which have no history records then you can change the inner join to left join. This will yield the max(value) of null for every Tag which has no history.

Oleg

Here is the updated solution which will work. It is based on some assumptions based on the conversation in the comments below. Please let me know if these are correct. The assumptions are as follows:

  1. There is a view named v_history. It is designed as though it does not need any parameters yet it fails to run if the where clause specifying at least one tag in the actual SQL statement querying the data from v_history is present. When statement fails to run to due its lacking the where clause with at least one tag, the view throws error stating the lack of a tag in the where clause as the reason for view failure. This is a very strange design, but lets live with it.
  2. I will assume that the view can return more than one record per tag and therefore, I will use the group by tag if I need to figure the max(value).

The solution below uses dynamic SQL. It is not the most efficient way of getting the data you need, but then again, I do not know the history behind the v_history design. With properly designed view, Kev's solution would work just fine.

declare @sql nvarchar(max);
declare @tags varchar(max);

-- populate the list of tags dynamically in one statement
select @tags = isnull(@tags + ', ', '') + '''' + Tag + '''' from Tags where shift = 'AM';

-- feed the list of tags to the final sql statement
select @sql = 'select Tag, max(value) from v_history where Tag in (' + @tags + ') group by Tag;';

-- execute the sql
exec sp_executesql @sql;

Oleg

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Kev Riley avatar image
Kev Riley answered

not sure if your query in the question is exactly as you have it in code, but to make it syntactically corrrect it needs to be more like

;with am (am_tag) as (select tag from tags where shift = 'Am')

select 
 h.tag, 
 max(value) 
from v_history h
where
 h.tag in (select am_tag from am)
group by
 h.tag

now is that still giving you an error/ or not giving you the results you want?

there is no need to use a CTE in this case, you could just simply have

select 
 h.tag, 
 max(value) 
from v_history h
where
 h.tag in (select tag from tags where shift = 'Am')
group by
 h.tag
3 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

TimothyAWiseman avatar image TimothyAWiseman commented ·
I am a fan of using CTEs to make code more readable, but in this case I think it makes it harder, not easier to read. The one without the CTE is shorter and more clear.
0 Likes 0 ·
Clint avatar image Clint commented ·
the example above was the way i first attempted this query.. however i get the following error OLE DB provider "INSQL" for linked server "INSQL" returned message "History queries must contain at least one valid tagname". thats what has me thinking it is going to require some sort of loop
0 Likes 0 ·
Kev Riley avatar image Kev Riley ♦♦ commented ·
where has this linked server come from? :) Also, what is v_history - is this a view or table?
0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.