SQL Server - Efficiently storing the results of a query in a tracking table - sql

I have been asked to keep track of how many times each item comes up within the results of a particular query. My thought is to just store the result of a query into a tracking table and then spit the results back to the caller. I am wondering what the most efficient method of storing these results would be since the result set could include up to 1000 records.
My plan is to pull the query results into a temp table and insert those results into the tracking table then return the temp table as the result of the SPROC. Something like this:
DECLARE #QueryTime datetime
SET #QueryTime = GETDATE()
DECLARE #Results TABLE (X nvarchar(255), Y nvarchar(255))
INSERT INTO #Results
SELECT X,Y FROM TableA
INSERT INTO TableB
SELECT X, #QueryTime FROM #Results
SELECT X, Y FROM #Results
Does anyone have a more efficient way to post the bulk result set into a tracking table?

You don't need the #Results table.
Directly inserting and selecting from TableA does the job and will most likely be the most efficient way.
DECLARE #QueryTime DATETIME
SET #QueryTime = GetDate()
INSERT INTO TableB
SELECT X, #QueryTime FROM TableA
SELECT X, Y FROM #TableA

If you are using Sql 2008, you could return the rows as XML. Then you would just have 1 row to insert in your tracking table.

Related

Need to log identifiers from select query recordset along with date/time stamp

I would like to log all records generated by a sql select statement in an SSRS report into a table for later reference at the time the report is run.
One idea is to append the unique ID to the reference table and then perform the full query with the additional data for the full record set, but i feel like there is probably a better way.
One way would be to use a STORED PROCEDURE for your SSRS report instead of hard coding the query in the RDL. Then, you could leverage the OUTPUT clause and log the query execution, and return the results. The proc would look something like this:
create procedure myProc (#param1 int)
as
begin
declare #resultTable table (id int, c1 char(4), c2 char(4))
insert into myloggingtable
output INSERTED.id, INSERTED.c2, INSERTED.c3 into #resultTable
select
id,
c1,
c2,
RunDateTime = getdate(),
from SomeTable
where id = #param1
select * from #resultTable
end
Here, I would have an auto-incremented key on the myloggingtable and the RunDateTime would be logged as the execution time.

How to selectively return rows inside a stored procedure on SQL Server?

I have a base stored procedure simply returning a select from the database, like this:
CREATE PROCEDURE MyProcedure
AS
BEGIN
SELECT * FROM MyTable
END
GO
But now I need to execute some logic for every row of my select. According to the result I need to return or not this row. I would have my select statement running with a cursor, checking the rule and return or not the row. Something like this:
CREATE PROCEDURE MyProcedure
AS
BEGIN
DECLARE CURSOR_MYCURSOR FOR SELECT Id, Name FROM MyTable
OPEN CURSOR_MYCURSOR
FETCH NEXT FROM CURSOR_MYCURSOR INTO #OUTPUT1, #OUTPUT2
WHILE (##FETCH_STATUS=0)
BEGIN
IF (SOME_CHECK)
SELECT #OUTPUT1, #OUTPUT2
ELSE
--WILL RETURN SOMETHING ELSE
END
END
GO
The first problem is that everytime I do SELECT #OUTPUT1, #OUTPUT2 the rows are sent back as different result sets and not in a single table as I would need.
Sure, applying some logic to a row sounds like a "FUNCTION" job. But I can't use the result of the function to filter the results being selected. That is because when my check returns false I need to select something else to replace the faulty row. So, I need to return the faulty rows so I can be aware of them and replace by some other row.
The other problem with this method is that I would need to declare quite a few variables so that I can output them through the cursor iteration. And those variables would need to follow the data types for the original table attributes and somehow not getting out of sync if something changes on the original tables.
So, what is the best approach to return a single result set based on a criteria?
Thanks in advance.
I recommend use of cursors but easy solution to your question would be to use table variable or temp table
DECLARE #MyTable TABLE
(
ColumnOne VARCHAR(20)
,ColumnTwo VARCHAR(20)
)
CREATE TABLE #MyTable
(
ColumnOne VARCHAR(20)
,ColumnTwo VARCHAR(20)
)
than inside your cursors you can insert records that match your logic
INSERT INTO #MyTable VALUES (#Output1, #Output2)
INSERT INTO #MyTable VALUES (#Output1, #Output2)
after you done with cursor just select everything from table
SELECT * FROM #MyTable
SELECT * FROM #MyTable

SQl: Update Table from a text File

Here's what I have to do :
I have a text file which has 3 columns: PID, X, Y.
Now I have two tables in my database:
Table 1 contains 4 columns: UID, PID, X, Y
Table 2 contains multiple columns, required ones being UID, X, Y
I need to update Table 2 with corresponding X and Y values.
I think we can use BULK INSERT for updating table 1, then some WHILE loop or something.
But I can't figure out exact thing.
CREATE PROCEDURE [dbo].[BulkInsert]
(
#PID int ,
#x int,
#y int,
)
AS
BEGIN
SET NOCOUNT ON;
declare #query varchar(max)
CREATE TABLE #TEMP
(
[PID] [int] NOT NULL ,
[x] int NOT NULL,
[y] int NOT NULL,
)
SET #query = 'BULK INSERT #TEMP FROM ''' + PathOfYourTextFile + ''' WITH ( FIELDTERMINATOR = '','',ROWTERMINATOR = ''\n'')'
--print #query
--return
execute(#query)
BEGIN TRAN;
MERGE TableName AS Target
USING (SELECT * FROM #TEMP) AS Source
ON (Target.YourTableId = Source.YourTextFileFieldId)
-- In the above line we are checking if the particular row exists in the table(Table1) then update the Table1 if not then insert the new row in Table-1.
WHEN MATCHED THEN
UPDATE SET
Target.PID= Source.PID, Target.x= Source.x, Target.y= Source.y
WHEN NOT MATCHED BY TARGET THEN
-- Insert statement
You can use this above approach to solve your problem. Hope this helps. :)
How are you going to run it ? From a stored procedure ?
To save some performance, I would have done BULK INSERT to temp table, then insert from temp table to Table 1 & 2.
It should look like this
INSERT INTO Table1 ( PID, X, Y)
SELECT PID, X, Y
FROM #tempTable
Some will tell that temp table are not good, but it really depend - if you file is big, reading it from disk will take time and you don't want to do it twice.
You don't need any loop to update table 2; all you need is insert from table 1.
Or, if you are trying to update existing rows in table 2, use an update query that joins on table 1. See this question for an example.
However, you should consider changing your database design, as it appears to be incorrect: you are storing X and Y in two places; they should only be stored in one table, and you should join to this table if you need to use them in conjunction with other data. If you did this, you wouldn't have to worry about messy issues of keeping the two tables in sync.

Insert into Table select result set from stored procedure but column count is not same

I need something like that which is of course not working.
insert into Table1
(
Id,
Value
)
select Id, value from
(
exec MySPReturning10Columns
)
I wanted to populate Table1 from result set returned by MySPReturning10Columns. Here the SP is returning 10 columns and the table has just 2 columns.
The following way works as long as table and result set from SP have same number of columns but in my case they are not same.
INSERT INTO TableWith2Columns
EXEC usp_MySPReturning2Columns;
Also, I want to avoid adding "." as linked server just to make openquery and openrowset work anyhow.
Is there a way not to have define table strucutre in temp table (all columns with datatypes and lenght)? Something like CTE.
You could use a temporary table as a go-between:
insert into #TempTable exec MySP
insert into Table1 (id, value) select id, value from #TempTable
You could solve the problem in two steps by doing the insert from the stored procedure into a temporary table, then do the insert selecting just the columns you want from the temporary table.
Information on temporary tables: http://www.sqlteam.com/article/temporary-tables
-- Well, declare a temp table or a table var, depending on the number of rows expected
-- from the SP. This table will be basically the result set of your SP.
DECLARE #spResult AS TABLE
(
ID INT,
VALUE FLOAT,
....
);
-- Get the result set of the SP into the temp table.
INSERT #spResult EXEC STORED_PROC;
-- Now you can query the SP's result set for ID and Value;
INSERT Table1 (ID, VALUE)
SELECT ID, VALUE FROM #spResult;
You dont need to create a temporary table, you can do it with single query by creating temporary view like this
with tempView as EXEC MySPReturning10Columns insert into Table1 select id, value from tempView
The temporary view disappears as soon as the statement finishes execution

How can one iterate over stored procedure results from within another stored procedure....without cursors?

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.