I have a number of vendors, call then V1, V2, V3, etc. that provide data to my team. That data is provided on a monthly basis, and each time we ingest it, the tables are read in as the same format: VENDOR_YYYY_MM (e.g., V1 for 2023-10 data would be V1_2023_10).
I've written out a query (see below) that gives me the names of each table that are the most recent:
use mydb
go
select
name
, ROW_NUMBER() over (partition by 1 order by name desc) as row_num
from sys.Tables
inner join (
select max(cast(cast(right(name, 4) as varchar(4)) + cast(SUBSTRING(name, len(name) - 6, 2) as varchar(2)) as numeric)) as max_yyyy_mm
from sys.Tables
where (name like 'V1_%' OR name like 'V2_%' OR name like 'V3_%' OR
name like 'V4_%' OR name like 'V5_%' OR name like 'V6_%'OR
name like 'V7_%')
) t
on cast(cast(right(name, 4) as varchar(4)) + cast(SUBSTRING(name, len(name) - 6, 2) as varchar(2)) as numeric) = t.max_yyyy_mm
WHERE (name like 'V1_%'
OR name like 'V2_%'
OR name like 'V3_%'
OR name like 'V4_%'
OR name like 'V5_%'
OR name like 'V6_%'
OR name like 'V7_%')
Note that name
is the table name, based on sys.tables
. This gives me the following table:
name | row_num |
---|---|
V1_202310 | 1 |
V2_202310 | 2 |
... | ... |
I need to dynamically take the value from the first row, where row_num = 1, and use that as the basis for a select statement, so I can select * from V1_202310
, then select * from V2_202310
, etc. I am unsure of how to accomplish this, and am slightly afraid of dynamic SQL. Any tips would be appreciated! My guess is I need to declare some sort of table_name
variable, but I'm unsure of how to do that in a situation like this.
3条答案
按热度按时间qnakjoqk1#
Hope this can help give an idea.
First we will create a temporary table to hold most recent table names.
Second step is to insert the recent table names into that temp table.
The third step would be then to declare a cursor, which you will use to iterate over the table names storede in the temp table.
And the last step is you would be constructing your dynamic sql statement for each table name within the cursor loop, while executing them with the loop.
Do not forget to close and deallocate the cursor, and also clean the temp table
mbyulnm02#
First, let's make perfectly clear: There is
no
way to read a table with dynamic namewithout
dynamic SQL.I will not cover your answer functionally, but I'll focus on your caution on dynamic-SQL. Know that if you take the following 2 precautions, you will be perfectly safe from its dangers, i.e. injection.
quotename(@yourVarHere)
function. See, Kreetchy's answer already did that. That means no hacker can write something "smart" that bypasses your code -quotename
makes sure its input gets appropriate brackets to stay just a simple object namevalues
are passed as parameters insp_executesql
. So let's say you want to do aselect * from @yourTableNameVar where column1=@col1Value
. You should NOT do a direct string concatenation like that:Instead, you use
sp_executesql
's second argument to define your parameter(s) and then you pass them to the procedure directly:Do these two things, and you have no reason to fear it.
mcvgt66p3#
Not a complete answer, so just community wiki, but one thing I would do is convert this:
To use a table-value constructor like this:
or without the wildcards in the data, like this:
This sets you up to also move these values to a real table and eventually be fully data-driven for this.
Note the
_
character also has special meaning for theLIKE
predicate, but not in a way that's likely to really matter here.