I have a stored procedure that returns a dataset from a dynamic pivot query (meaning the pivot columns aren't know until run-time because they are driven by data).
The first column in this dataset is a product id. I want to join that product id with another product table that has all sorts of other columns that were created at design time.
So, I have a normal table with a product id column and I have a "dynamic" dataset that also has a product id column that I get from calling a stored procedure. How can I inner join those 2?
Dynamic SQL is very powerfull, but has some severe draw backs. One of them is exactly this: You cannot use its result in ad-hoc-SQL.
The only way to get the result of a SP into a table is, to create a table with a fitting schema and use the INSERT INTO NewTbl EXEC... syntax...
But there are other possibilities:
1) Use SELECT ... INTO ... FROM
Within your SP, when the dynamic SQL is executed, you could add INTO NewTbl to your select:
SELECT Col1, Col2, [...] INTO NewTbl FROM ...
This will create a table with the fitting schema automatically.
You might even hand in the name of the new table as a paramter - as it is dynamic SQL, but in this case it will be more difficult to handle the join outside (must be dynamic again).
If you need your SP to return the result, you just add SELECT * FROM NewTbl. This will return the same resultset as before.
Outside your SP you can join this table as any normal table...
BUT, there is a big BUT - ups - this sounds nasty somehow - This will fail, if the tabel exists...
So you have to drop it first, which can lead into deep troubles, if this is a multi-user application with possible concurrencies.
If not: Use IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='NewTbl') DROP TABLE NewTbl;
If yes: Create the table with a name you pass in as parameter and do you external query dynamically with this name.
After this you can re-create this table using the SELECT ... INTO syntax...
2) Use XML
One advantage of XML is the fact, that any structure and any amount of data can be stuffed into one single column.
Let your SP return a table with one single XML column. You can - as you know the schema now - create a table and use INSERT INTO XmlTable EXEC ....
Knowing, that there will be a ProductID-element you can extract this value and create a 2-column-derived-table with the ID and the depending XML. This is easy to join.
Using wildcards in XQuery makes it possible to query XML data without knowing all the details...
3) This was my favourite: Don't use dynamic queries...
Related
this is my first question here. I am very new into SQL Server and T-SQL.
I would like to create a table, with a column that is using data from another column. I thought I could use select function, but it is not allowed.
How to do it?
It is very simple to create view in this way, but I would like to have a table not view.
It should look like
Column A, ColumnB,
Column C=select count(*) from [another table] where....
Could you please advise?
SELECT [COLUMN A],[COLUMN B],COUNT(*) as [COLUMN C]
INTO [destination table] FROM [another table] where...
You should use an alias
You create a table using the create table syntax because you will need to define the field names and sizes. Look the syntax up in Books Online. Do not ever use SELECT INTO unless you are creating a staging table for one-time use or a temp table. It is not a good choice for creating a new table. Plus, you don't say where any of the other columns come from except the column one, so it is may be impossible to properly set up the correct field sizes from the initial insert. Further, well frankly you should take the time to think about what columns you need and what data types they should be, it is irresponsible to avoid doing this for a table that will be permanently used.
To populate you use the Insert statement with a select instead of the values statement. If only column c come from another table, then it might be something like":
Insert table1 (colA, Colb, colC)
select 'test', 10, count(*)
from tableb
where ...
If you have to get the data from multiple tables, then you may need a join.
If you need to maintain the computed column as the values change in TableB, then you may need to write triggers on TableB or better (easier to develop and maintain and less likely to be buggy or create a data integrity problem) use a view for this instead of a separate table.
I have a big query to get multiple rows by id's like
SELECT *
FROM TABLE
WHERE Id in (1001..10000)
This query runs very slow and it ends up with timeout exception.
Temp fix for it is querying with limit, break this query into 10 parts per 1000 id's.
I heard that using temp tables may help in this case but also looks like ms sql server automatically doing it underneath.
What is the best way to handle problems like this?
You could write the query as follows using a temporary table:
CREATE TABLE #ids(Id INT NOT NULL PRIMARY KEY);
INSERT INTO #ids(Id) VALUES (1001),(1002),/*add your individual Ids here*/,(10000);
SELECT
t.*
FROM
[Table] AS t
INNER JOIN #ids AS ids ON
ids.Id=t.Id;
DROP TABLE #ids;
My guess is that it will probably run faster than your original query. Lookup can be done directly using an index (if it exists on the [Table].Id column).
Your original query translates to
SELECT *
FROM [TABLE]
WHERE Id=1000 OR Id=1001 OR /*...*/ OR Id=10000;
This would require evalutation of the expression Id=1000 OR Id=1001 OR /*...*/ OR Id=10000 for every row in [Table] which probably takes longer than with a temporary table. The example with a temporary table takes each Id in #ids and looks for a corresponding Id in [Table] using an index.
This all assumes that there are gaps in the Ids between 1000 and 10000. Otherwise it would be easier to write
SELECT *
FROM [TABLE]
WHERE Id BETWEEN 1001 AND 10000;
This would also require an index on [Table].Id to speed it up.
I'm creating a data validation procedure for a database, using various models, etc. in the database.
I've created a temp table with a model, a sequence, and 3 columns.
In each of these columns I have the qualified column name (table.column) to use in my query, or a null value. Here's the temp_table structure:
create table #temp_table(model nvarchar(50), seq nvarchar(50), col nvarchar(100), col2 nvarchar(100) , col3 nvarchar(100))
In my dynamic sql I have a join something like this (exteremely simplified):
select *
from
original_table
inner join
...
#temp_table
on
original_table.models = #temp_table.models
inner join
set_model
on
original_tables.models = set_model.models
and #temp_table.col = set_model.val
and #temp_table.col2 = set_model.val2
and #temp_table.col3 = set_model.val3
What I'm working on has many more tables (hence the ... in the middle of the query), so, we'll just assume that all the tables are present and all the columns are valid.
Because #temp_table.col stores a value, when being join to set_model.val the comparison will look something like 'Buildings.year_id' = 2014.
Is there a way to force my dynamic query to use the value in #temp_table.col as part of the join condition?
For example:
If in the query above #temp_table.col = 'Buildings.year_id'
how do I make the join evaluate Buildings.year_id = set_model.val
rather than 'Buildings.year_id' = 2014?
I was trying to create a query which had a different query plan based upon the row queried.
I found a workaround (creating a cursor and looping through n different tables and appending each dynamic query with a ' union '), but I came back and thought about the problem I ran into for a little while.
I realized that I was trying to dynamically create a query based upon data from the query I was using. As a result, no effective query plan could be created, as it would need to run a unique query based upon each row.
If the query had been able to work, it would've been extremely inefficient (as each row would make its own 'select' statement).
Regardless, the question itself was based on bad/incomplete logic.
Im using pivot runtime and after running the same i want to store the result set in a table. so i need to create a table dynamically based on the result set. Any ideas?
You can use a SELECT ... INTO statement.
Example:
SELECT * INTO NewTable FROM #TempTableResult
This statement will create a new table called NewTable automatically based on the structure of #TempTableResult with all the data you get from the SELECT.
The columns of the NewTable will be the same as the output of the SELECT statement, with the same data types.
EDIT: Note that the SELECT ... INTO statement fails if the destination table already exists, so remember to drop it before running the query, or you may use a dynamically generated table name instead.
For some background... I have a collection of tables, and I would like a trigger on each table for INSERT, UPDATE, DELETE. SQL Server version is SQL 2005.
I have an audit table Audit that contains a column called Detail. My end goal is to create a trigger that will get the list of columns of its table, generate a dynamic select query from either Inserted, Updated, or Deleted, do some string concatenation, and dump that value into the Detail column of Audit.
This is the process I was thinking:
Get columns names in table for sys.columns
Generate dynamic sql SELECT query based on column names
Select from Inserted
foreach row in results, concatenate column values into single variable
Insert variable data into Detail column
So, the questions:
Is this the best way to accomplish what I'm looking to do? And the somewhat more important question, how do I write this query?
You could use FOR XML for this, and just store the results as an XML document.
SELECT *
FROM Inserted
FOR XML RAW
will give you attibute-centric xml, and
SELECT *
FROM Inserted
FOR XML PATH('row')
will give you element-centric xml. Much easier than trying to identify the columns and concatenate them.