I'm looking for some views on how to go about resolving this challenge. I have a variable say #Var1 which holds a SQL statement within it.
Example
#Var1 = `SELECT * from another_table WHERE City IS NOT NULL AND Address IS NOT NULL`
When I execute this variable
EXECUTE sp_executesql #Var1
I get the desired result, City and Address excluding NULL values.
I am hoping to update a existing table (tbl1) based on execution result of #Var1:
Something like:
UPDATE TABLE tbl1 AS (EXECUTE sp_executesql #Var1)
Is something like this even possible? Or what approach can I take to get the result of #Var1 into tbl1?
Thanks in advance.
My apologies for including links for each step but they deserve the credit.
There are 2 steps. Insert into a temp-table then merge the data from that temp-table into your final table.
You will have to insert into a Temp Table first.
INSERT INTO #TABLE EXEC #query with SQL Server 2000
Then you have to merge that data into you main table.
SQL MERGE statement to update data
try This
UPDATE tbl1
SET Column1= b.Column1,
SET Column2= b.Column2,
SET Column3= b.Column3,
FROM tbl1 a
INNER JOIN (
SELECT Column1,Column2,Column3
FROM another_table WHERE City IS NOT NULL AND Address IS NOT NULL ) b ON a.city_Id = b.city_Id
Related
I'm not sure if this is something I should do in T-SQL or not, and I'm pretty sure using the word 'iterate' was wrong in this context, since you should never iterate anything in sql. It should be a set based operation, correct? Anyway, here's the scenario:
I have a stored proc that returns many uniqueidentifiers (single column results). These ids are the primary keys of records in a another table. I need to set a flag on all the corresponding records in that table.
How do I do this without the use of cursors? Should be an easy one for you sql gurus!
This may not be the most efficient, but I would create a temp table to hold the results of the stored proc and then use that in a join against the target table. For example:
CREATE TABLE #t (uniqueid int)
INSERT INTO #t EXEC p_YourStoredProc
UPDATE TargetTable
SET a.FlagColumn = 1
FROM TargetTable a JOIN #t b
ON a.uniqueid = b.uniqueid
DROP TABLE #t
You could also change your stored proc to a user-defined function that returns a table with your uniqueidentifiers. You can joing directly to the UDF and treat it like a table which avoids having to create the extra temp table explicitly. Also, you can pass parameters into the function as you're calling it, making this a very flexible solution.
CREATE FUNCTION dbo.udfGetUniqueIDs
()
RETURNS TABLE
AS
RETURN
(
SELECT uniqueid FROM dbo.SomeWhere
)
GO
UPDATE dbo.TargetTable
SET a.FlagColumn = 1
FROM dbo.TargetTable a INNER JOIN dbo.udfGetUniqueIDs() b
ON a.uniqueid = b.uniqueid
Edit:
This will work on SQL Server 2000 and up...
Insert the results of the stored proc into a temporary table and join this to the table you want to update:
INSERT INTO #WorkTable
EXEC usp_WorkResults
UPDATE DataTable
SET Flag = Whatever
FROM DataTable
INNER JOIN #WorkTable
ON DataTable.Ket = #WorkTable.Key
If you upgrade to SQL 2008 then you can pass table parameters I believe. Otherwise, you're stuck with a global temporary table or creating a permanent table that includes a column for some sort of process ID to identify which call to the stored procedure is relevant.
How much room do you have in changing the stored procedure that generates the IDs? You could add code in there to handle it or have a parameter that lets you optionally flag the rows when it is called.
Use temporary tables or a table variable (you are using SS2005).
Although, that's not nest-able - if a stored proc uses that method then you can't dumpt that output into a temp table.
An ugly solution would be to have your procedure return the "next" id each time it is called by using the other table (or some flag on the existing table) to filter out the rows that it has already returned
You can use a temp table or table variable with an additional column:
DECLARE #MyTable TABLE (
Column1 uniqueidentifer,
...,
Checked bit
)
INSERT INTO #MyTable
SELECT [...], 0 FROM MyTable WHERE [...]
DECLARE #Continue bit
SET #Continue = 1
WHILE (#Continue)
BEGIN
SELECT #var1 = Column1,
#var2 = Column2,
...
FROM #MyTable
WHERE Checked = 1
IF #var1 IS NULL
SET #Continue = 0
ELSE
BEGIN
...
UPDATE #MyTable SET Checked = 1 WHERE Column1 = #var1
END
END
Edit: Actually, in your situation a join will be better; the code above is a cursorless iteration, which is overkill for your situation.
I have a really weird and complex requirement that I need help with. I have a table let's say Tasks that contains all the tasks for a user/system. I need to filter out the tasks per user and show it in UI. But here is the scene, the Tasks table contains a column base_table that stores the table name (real SQL Server table) on which it is based. It also stores the base table id which navigates to a particular record in the base table. Now I need to add some filter in the base table and if it satisfies the task would get retrieved.
I did try to put up a procedure which would hit a select query against base table and also check conditions.
CREATE PROCEDURE gautam_dtTable_test
(#TableName AS nvarchar(max))
AS
BEGIN try
declare #sql nvarchar(max)
declare #ret tinyint
set #ret = 0
set #sql = 'select 1 where exists (Select top 1 Id from ' + #TableName+' where some_condition)';
Exec sp_executesql #sql, N'#var tinyint out', #ret out
return #ret
end try
begin catch
return 0
end catch
I have used the procedure to input table name and hit some conditions and return a flag, 1/0 kind of thing. I also want to use try catch so that if there is any error, it would return false.
That's why I have used the procedure, not function. But seems like we can use this procedure into sql statement. Overall what I have in my mind is
Select *
from tasks
where some_conditions
and procedure/function_to_check(tasks.base_table)
Key issues with my approach
The base_table name could be invalid, so are some columns in it. So, I would love to use a try-catch.
Need to Embed it as sub-query to avoid parallel operations. But it seems tough when your procedure/function have EXEC and sp_executesql defined.
Any kind of help is appreciated. Thanks in advance!
The question as stated is a bit unclear so I am going to make some assumptions here. It looks like you are trying achieve the following:
First it seems you are trying to only return task in your task table where the ‘base_table’ column value references a valid SQL Server table.
Secondly if I understand the post correctly, based on the where clause condition passed to the tasks table you are trying to determine if the same columns exists in your base table.
The first part is certainly doable. However, the second part is not since it would require the query to somehow parse itself to determine what columns are being filtered on.
The following query show how you can retrieve only tasks for which there is a valid corresponding table.
SELECT *
FROM [dbo].[tasks] ts
CROSS APPLY (
SELECT [name]
FROM sys.objects WHERE object_id = OBJECT_ID('[dbo].' + QUOTENAME(ts.base_table)) AND type in (N'U')
) tb
If the field(s) you are trying to filter on is known up front (i.e. you are not trying to parse based of the tasks table) then you can modify the above query to pass the desired columns you want to check as follow:
DECLARE #columnNameToCheck NVARCHAR(50) = 'col2'
SELECT ts.*
FROM [dbo].[tasks] ts
CROSS APPLY (
SELECT [name]
FROM sys.objects WHERE object_id = OBJECT_ID('[dbo].' + QUOTENAME(ts.base_table)) AND type in (N'U')
) tb
CROSS APPLY (
SELECT [name]
FROM sys.columns WHERE object_id = OBJECT_ID('[dbo].' + QUOTENAME(ts.base_table)) AND [name] = #columnName
This is the data I have pulled from powershell and inserted it into a #temptable:
Name : SULESRKMA
Location : Leisure Services - Technology Services
Shared : False
ShareName :
JobCountSinceLastReset : 0
PrinterState : 131072
Status : Degraded
Network : False
I'm while looping through the data and have stripped the values from the identifiers. I'd like to use these identifiers to insert the values into a table with identical Column names to the identifiers. So for example, I have a variable called #identifier = "Name" and a temp table #printers with a column name of Name. I'd like to do something like:
SELECT --select statement
INSERT INTO #printers(#identifier)
But This doesn't seem to work, unsurprisingly. Is there a way to accomplish this? (The #identifier variable will be changing to the other identifiers in the data throughout the course of the while loop.)
Any alternate suggestions that don't even involve using this sort of method are welcome. My ultimate goal is just to get this data as a row into a table.
(I'm currently using Microsoft SQL Server Management Studio if that matters)
First, it's unlikely you need to loop over anything in this situation. Think set based operations when you think about SQL.
INSERT INTO #temptable (Column1Name, Column2Name, Column3Name)
VALUES (#identifer, #anotherIdentifier, #someOtherIdentifier)
--optional clauses
WHERE Column1Name = 'some value' OR Column1Name = #someIdentifier
Or you can SELECT INTO
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier
INTO #temptable
It's important that you have a value in your SELECT INTO for each column in the table which you are trying to add the data to. So, for example, if there were 4 columns in #temptable and you only had 3 values to insert (columns 1, 2 , and 3) then you'd need to NULL column 4 or set it statically.
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
NULL
INTO #temptable
--or
SELECT
#identifier,
#anotherIdentifer,
#someOtherIdentifier,
'static value'
INTO #temptable
EDIT
If you want to use a varible to speciy the column that you want to insert into, you have to use dynamic sql. Here is an example:
if object_id ('tempdb..#tempTable') is not null drop table #tempTable
create table #tempTable (Column1Name int, Column2Name int, Column3Name int)
declare #columnName varchar(64) = 'Column1Name'
declare #sql varchar(max)
set #sql =
'insert into #tempTable (' + #columnName + ')
select 1'
exec(#sql)
select * from #tempTable
The problem im trying to solve is about avoiding duplicate data getting into my table. I'm using xml to send bulk data to a stored procedure. The procedure I wrote works with 100, 200 records. But when it comes to 20000 of them there is a time out exception.
This is the stored procedure:
DECLARE #TEMP TABLE (Page_No varchar(MAX))
DECLARE #TEMP2 TABLE (Page_No varchar(MAX))
INSERT INTO #TEMP(Page_No)
SELECT
CAST(CC.query('data(PageId)') AS NVARCHAR(MAX)) AS Page_No
FROM
#XML.nodes('DocumentElement/CusipsFile') AS tt(CC)
INSERT INTO #TEMP2(Page_No)
SELECT Page_No
FROM tbl_Cusips_Pages
INSERT INTO tbl_Cusips_Pages(Page_No, Download_Status)
SELECT Page_No, 'False'
FROM #TEMP
WHERE Page_No NOT IN (SELECT Page_No FROM #TEMP
INTERSECT
SELECT Page_No FROM #TEMP2)
How can I solve this? Is there a better way to write this procedure?
As was already suggested, NVARCHAR(MAX) column/variable is very slow and has limited options. If you can change it, it would help a lot.
MERGE tbl_Cusips_Pages
USING (
SELECT
CAST(CC.query('data(PageId)') AS NVARCHAR(4000))
FROM
#XML.nodes('DocumentElement/CusipsFile') AS tt(CC)
) AS source (Page_No)
ON tbl_Cusips_Pages.Page_No = source.Page_No
WHEN NOT MATCHED BY TARGET
THEN INSERT (Page_No, Download_Status)
VALUES (source.Page_No, 'false')
Anyway, your query is not that bad either, just put the queries directly into the third one (TEMP2 one for sure) instead of inserting the data into the table variables. Table variables are quite slow in comparison.
Replace last INSERT Statement with following Script, I have replace IN Clause With NOT EXISTS that may help you for better performance.
DECLARE #CommanPageNo TABLE (Page_No varchar(MAX))
INSERT INTO #CommanPageNo SELECT Page_No FROM #TEMP
INTERSECT
SELECT Page_No FROM #TEMP2
INSERT INTO tbl_Cusips_Pages(Page_No, Download_Status)
SELECT Page_No, 'False'
FROM #TEMP
WHERE NOT EXISTS (SELECT 1 FROM #CommanPageNo WHERE Page_No=#CommanPageNo.Page_No)
UPDATE users
SET field = my_sp()
in SQL Server 2005. Apparently I can't do this and have to use some form of EXEC. Can anyone help me out and let me know how to do this? This should be some easy rep.
To assign value you need to use sql function. it is impossible to assign value from stored procedure.
Here is link how to create it.
you need to write a scalar function that takes some parameters (or even zero) and returns what you need.
You could store the output of the stored procedure in a temp table, then use that temp table as the basis for your update. As an example, the code below assumes your proc returns a record set with two integers.
create table #t (
ColumnA int,
ColumnB int
)
insert into #t
(ColumnA, ColumnB)
exec my_sp
update u
set field = t.ColumnB
from users u
inner join #t t
on u.UserID = t.ColumnA
drop table #t