Temp table empty after sql insert exec - sql

Very confused as to why the final select * from #tempTbl is empty.
When I run this, everything else works fine, but I need the results in a temp table to continue with the next step of the stored procedure. I've been searching every forum possible including this one, and cannot fix this issue. Any help would be greatly appreciated.
CREATE TABLE #tempTbl
(
POID VARCHAR(15),
UPC VARCHAR(15),
QtyOrdered int,
DateOrdered date,
Closed bit
)
insert into #tempTbl (POID, UPC, QtyOrdered, DateOrdered, Closed)
exec dbo.sp_executesql #as4sql;
--exec (#as4sql)
select * from #tempTbl
Update:
Here's my set:
set #as4sql = 'INSERT INTO tblPODetail
(POID, UPC, QtyOrdered, DateOrdered, Closed)
(SELECT pod.PONumber, pod.UPC, pod.QtyOrdered, 1, 0
FROM [awx].[dbo].[POLines] pol
JOIN [awx].[dbo].[PODetails] pod
ON pol.PONumber = pod.PONumber
LEFT JOIN tblPODetail p
ON p.POID = pod.PONumber
WHERE p.POID IS NULL...

Related

How can I solve my performance issue in my stored procedure?

How can I get better performance with my sql query in a SP? It has a lot of memory usage.if you look at below my execution pan you will see that :
IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xyzType = #xyzType AND CustomerId = #CustomerId)[/code]
has alot of memory usage. How can I reduce that?
ALTER PROCEDURE [Common].[SaveCustomerxxxIds]
(
#xyzType NVARCHAR(128),
#CustomerId INT,
#xxxId INT OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM Common.[CustomerxxxIds] WHERE xxxType = #xxxType AND CustomerId = #CustomerId)
BEGIN
INSERT INTO Common.[CustomerxxxIds]
([xxxId]
,[CustomerId]
,[xxxType])
VALUES
(0
,#CustomerId
,#xxxType)
END
UPDATE Common.[CustomerxxxIds]
SET [xxxId] = ([xxxId]) + 1
WHERE [xxxType] = #xxxType
AND CustomerId = #CustomerId
SELECT #xxxId = xxxId
FROM Common.[CustomerxxxIds]
WHERE [xxxType] = #xxxType
AND CustomerId = #CustomerId
END
You can do things to avoid "re-read" of the table to get the output value.
After the INSERT
( INSERT INTO Common.[CustomerxxxIds])
Use SCOPE_IDxxx() to get the newly created surrogate key.
The above will only work for IDxxx columns. From your question, you may not actually have an IDxxx column.
See
https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-idxxx-transact-sql?view=sql-server-2017
.........
with the UPDATE and/or INSERT, you could use OUTPUT functionality to get the value.
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-2017
This AVOIDS the last select statement (the "re-read" as I am calling it) to get the desired output value.
Obviously completely removing a SELECT statement will improve performance.
..
Below is a simple but complete Northwind database example of using OUTPUT for INSERT and UPDATE
SELECT 'Before' as Looksie, [ShipperID]
,[CompanyName]
,[Phone]
FROM [Northwind].[dbo].[Shippers]
--
DECLARE #MyInsertAuditTable table( AuditShipperID INT,
AuditCompanyName nvarchar(40),
AuditPhone nvarchar(24));
INSERT [Northwind].[dbo].[Shippers] (CompanyName , Phone )
OUTPUT INSERTED.ShipperID, INSERTED.CompanyName, INSERTED.Phone
INTO #MyInsertAuditTable (AuditShipperID, AuditCompanyName , AuditPhone )
SELECT TOP 1
--(SELECT MAX(ShipperID) + 1 from dbo.Shippers )
'Shipper' + LEFT(CONVERT(VARCHAR(38), NEWID()), 12)
, '(555) 555-5555'
FROM sys.objects
--Display the result set of the table variable.
SELECT AuditShipperID, AuditCompanyName, AuditPhone FROM #MyInsertAuditTable;
DECLARE #MyUpdateAuditTable table( AuditShipperID INT,
AuditCompanyName nvarchar(40),
AuditOldPhone nvarchar(24),
AuditNewPhone nvarchar(24));
UPDATE [Northwind].[dbo].[Shippers]
SET Phone = '(777) 555-7777'
OUTPUT inserted.ShipperID, inserted.CompanyName ,
deleted.Phone,
inserted.Phone
INTO #MyUpdateAuditTable ( AuditShipperID, AuditCompanyName, AuditOldPhone , AuditNewPhone)
FROM [Northwind].[dbo].[Shippers] shippers
JOIN #MyInsertAuditTable insAudit on shippers.ShipperID = insAudit.AuditShipperID
SELECT * from #MyUpdateAuditTable
SELECT 'After' as Looksie, [ShipperID]
,[CompanyName]
,[Phone]
FROM [Northwind].[dbo].[Shippers]
--
Results
Looksie ShipperID CompanyName Phone
Before 1 Speedy Express (503) 555-9831
Before 2 United Package (503) 555-3199
Before 3 Federal Shipping (503) 555-9931
..
AuditShipperID AuditCompanyName AuditPhone
9 Shipper3C062D46-EEA (555) 555-5555
...
AuditShipperID AuditCompanyName AuditOldPhone AuditNewPhone
9 Shipper3C062D46-EEA (555) 555-5555 (777) 555-7777
..
Looksie ShipperID CompanyName Phone
After 1 Speedy Express (503) 555-9831
After 2 United Package (503) 555-3199
After 3 Federal Shipping (503) 555-9931
After 9 Shipper3C062D46-EEA (777) 555-7777
You can achieve this by changing SELECT * to SELECT 1. it might help
IF NOT EXISTS (SELECT 1 FROM Common.[CustomerxxxIds]
WHERE xyzType = #xyzType AND CustomerId = #CustomerId)
Try this
ALTER PROCEDURE [Common].[SaveCustomerxxxIds]
(
#xyz NVARCHAR(128),
#CustomerId INT,
#xxxId INT OUTPUT
)
AS
BEGIN
set #xxxId=null
--Get xxxId
SELECT #xxxId=[xxxId] FROM Common.[CustomerxxxIds] WHERE xyz = #xyz AND CustomerId = #CustomerId
--If #xxxId means no record we should insert
if (#xxxId is null)
begin
--When insert we always insert xxxId as 0 then update to one then we collect the value (one) from db and return it.
--Better set value directly as one insert it to DB and return it as one. Instead of insert, update, select
--just insert
set #xxxId = 1
INSERT INTO Common.[CustomerxxxIds]
([xxxId]
,[CustomerId]
,[xyz])
VALUES
(#xxxId
,#CustomerId
,#xyz)
end
else
begin
--If we have the value we add one to it update the record and return it.
--better than update table then select.
--We already have the value we add one to it then update table and return the value we have
set #xxxId+=1
UPDATE Common.[CustomerxxxIds] SET [xxxId] = #xxxId
WHERE [xyz] = #xyz AND CustomerId = #CustomerId
END
end

IF EXISTS (SELECT) in SQL Server not working as expected

I have a code like this:
IF EXISTS (SELECT * FROM table WHERE id = #id)
BEGIN
UPDATE table
SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO [table] ([id], [name], [stock])
VALUES (#id, #name, #stock)
END
But, this code isn't working and I am unable to find the root cause for the same. Can someone please help me?
I do not see any error in your code, I tried to replicate the process and it is working fine for me. Can you tell me what is the error you are facing exactly.
The following is the code I tried to replicate your scenario:
CREATE TABLE stocks (
id INT
,NAME VARCHAR(100)
,stock BIGINT
)
CREATE PROCEDURE InsertStocks #id INT
,#name VARCHAR(100)
,#stock BIGINT
AS
BEGIN
IF EXISTS (
SELECT *
FROM stocks
WHERE id = #id
)
BEGIN
UPDATE stocks
SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO stocks (
[id]
,[name]
,[stock]
)
VALUES (
#id
,#name
,#stock
)
END
END
INSERT INTO stocks
VALUES (
1
,'abc'
,200
)
INSERT INTO stocks
VALUES (
2
,'abc'
,300
)
INSERT INTO stocks
VALUES (
3
,'abc'
,500
)
EXEC Insertstocks 1
,'abc'
,700
This is updated successfully in my case.
table is a reserved keyword. so I guess you have a trivial syntax error: Incorrect syntax near the keyword 'table'. Wrap it with [], as you already did for INSERT statement
IF EXISTS (
SELECT * FROM [table] WHERE id = #id)
BEGIN
UPDATE [table] SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO [table] ([id]
,[name]
,[stock])
VALUES
(
#id,#name,#stock
)
END
Your code and syntax is correct. Let's see a sample example:
if EXISTS(select * from dbo.tbName where Id=1)
BEGIN
print 1
END
ELSE
BEGIN
print 2
END

SQL Server improve query performance #Temp Table, Bulk insert

I am working on an old auditing stored procedure that is taking a long time to get data causing timeouts on the system. We have managed to get the time down from over 20 minutes to running just over a minute, this is still too long.
I am running on SQL Server 2008 R2.
My question is is there anything I could do to improve the speed of the query? In particular the temporary tables and the a bulk insert statement.
SELECT
dbo.[Audit Result Entry Detail].PK_ID,
+ every other value in the table (all values required)
INTO
#temp5
FROM
dbo.[Audit Result Entry Detail]
An INNER JOIN then occurs on dbo.[Audit Register] another select occurs and added to another temporary table #result is created.
Result temporary table gets the old and new result values for comparison. Below I have provided what event occurs on #temp5. Note these are just snippets; the stored procedure is way too big to post everything.
SELECT
RED.[FK_RegisterID],
total of a 106 rows are selected here :(
FROM
#temp5 AS RED
LEFT JOIN
#temp5 AS OLD ON RED.IdentityColumn = OLD.IdentityColumn
LEFT JOIN
[Audit Register] AS REG ON REG.PK_ID = RED.FK_RegisterID
SELECT MAX(PK_ID)
OVER (PARTITION BY FK_RegisterID) AS MAX_PK_ID
FROM #temp5
DROP TABLE #temp5
The second part of my question is a bulk insert into this table created at the very top of the stored procedure
DECLARE #AuditOverView TABLE
(
FK_RegisterID INT,
Audit_Date DATETIME,
ContextUser NVARCHAR(30),
Original_Value NVARCHAR(255),
New_Value NVARCHAR(255),
Assay NVARCHAR(200),
Inst NVARCHAR(40),
LotLevel NVARCHAR(3),
Lot_ExpiryDate NVARCHAR(10),
Lot_Number NCHAR(50),
Audit_Type NVARCHAR(10),
Partnumber INT,
[Type] NVARCHAR(50),
SubType NVARCHAR(50)
)
The insert statement below:
INSERT INTO #AuditOverView
SELECT DISTINCT
t.FK_RegisterID,
t.Audit_Date,
t.ContextUser,
CONVERT(NVARCHAR, Original_Date_Run, 127) AS Original_Value,
CONVERT(NVARCHAR, New_Date_Run, 127) AS New_Value,
t.Assay AS 'Assay',
Instrument AS 'Inst',
'1' AS 'LotLevel',
Lot1_Expiry_Date AS 'Lot_ExpiryDate',
Lot1Number AS 'Lot_Number',
t.Audit_Type,
part_number AS Partnumber,
'QC Result' AS [Type],
'Result Date' AS SubType
FROM
#Result AS t
INNER JOIN
(SELECT MAX(Audit_Date) AS DATE, FK_RegisterID
FROM #Result
GROUP BY FK_RegisterID) dt ON t.FK_RegisterID = dt.FK_RegisterID
AND t.Audit_Date = dt.DATE
WHERE
RTRIM(Lot1Number) != ''
AND (CONVERT(NVARCHAR, Original_Date_Run, 120) != CONVERT(NVARCHAR, New_Date_Run, 120)
OR t.Audit_Type = 'i'
OR t.Audit_Type = 'd')
This insert statement occurs about 50 times and the only line changes occur are:
'Result Date' AS SubType
CONVERT(NVARCHAR, Original_Date_Run, 120) != CONVERT(NVARCHAR, New_Date_Run, 120)
I can provide more information if needed. Any help would be much appreciated to improve performance.

Must declare the scalar variable #tempTbl

I get this error even though i have tried what other post suggested still the same error
but when i run select it works OK...
any help would be greatly appreciated
ALTER PROCEDURE UpdateCustomers
#XML AS XML
AS
DECLARE #tempTbl TABLE(
tblID INT ,
Customer_name NVARCHAR(30),
Customer_Code NVARCHAR(10)
)
INSERT INTO #tempTbl(tblID, Customer_name, Customer_Code)
SELECT
Item.element.value('#tblID', 'int'),
Item.element.value('#Customer_name', 'nvarchar(30)'),
Item.element.value('#Customer_Code', 'nvarchar(10)')
FROM
#xml.nodes('/root/item') AS Item(element)
--SELECT * FROM #tempTbl---it runs ok
UPDATE dbo.Customers
SET
dbo.Customers.Customer_name = #tempTbl.Customer_name,
dbo.Customers.Customer_Code = #tempTbl.Customer_Code
from dbo.Customers
inner join #tempTbl
on Customers.tblID =#tempTbl.tblID
Try aliasing the table variable in the UPDATE
e.g.
UPDATE dbo.Customers
SET
dbo.Customers.Customer_name = tmp.Customer_name,
dbo.Customers.Customer_Code = tmp.Customer_Code
from dbo.Customers
inner join #tempTbl tmp
on Customers.tblID = tmp.tblID

How to update a column fetched by a cursor in TSQL

Before I go any further: Yes, I know that cursors perform poorly compared with set-based operations. In this particular case I'm running a cursor on a temporary table of 100 or so records, and that temporary table will always be fairly small, so performance is less crucial than flexibility.
My difficulty is that I'm having trouble finding an example of how to update a column fetched by a cursor. Previously when I've used cursors I've retrieved values into variables, then run an update query at each step based upon these values. On this occasion I want to update a field in the temporary table, yet I can't figure out how to do it.
In the example below, I'm trying to update the field CurrentPOs in temporary table #t1, based upon a query that uses #t1.Product_ID to look up the required value. You will see in the code that I have attempted to use the notation curPO.Product_ID to reference this, but it doesn't work. I have also attempted to use an update statement against curPO, also unsuccessfully.
I can make the code work by fetching to variables, but I'd like to know how to update the field directly.
I think I'm probably missing something obvious, but can anyone help?
declare curPO cursor
for select Product_ID, CurrentPOs from #t1
for update of CurrentPOs
open curPO
fetch next from curPO
while ##fetch_status = 0
begin
select OrderQuantity = <calculation>,
ReceiveQuantity = <calculation>
into #POs
from PurchaseOrderLine POL
inner join SupplierAddress SA ON POL.Supplier_ID = SA.Supplier_ID
inner join PurchaseOrderHeader POH ON POH.PurchaseOrder_ID = POL.PurchaseOrder_ID
where Product_ID = curPO.Product_ID
and SA.AddressType = '1801'
update curPO set CurrentPOs = (select sum(OrderQuantity) - sum(ReceiveQuantity) from #POs)
drop table #POs
fetch next from curPO
end
close curPO
deallocate curPO
After doing a bit more googling, I found a partial solution. The update code is as follows:
UPDATE #T1
SET CURRENTPOS = (SELECT SUM(ORDERQUANTITY) - SUM(RECEIVEQUANTITY)
FROM #POS)
WHERE CURRENT OF CURPO
I still had to use FETCH INTO, however, to retrieve #t1.Product_ID and run the query that produces #POs, so I'd still like to know if it's possible to use FETCH on it's own.
Is this what you want?
declare curPO cursor
for select Product_ID, CurrentPOs from #t1
for update of CurrentPOs
open curPO
fetch next from curPO
while ##fetch_status = 0
begin
update curPO set CurrentPOs =
(select sum(<OrderQuantityCalculation>)
from PurchaseOrderLine POL
inner join SupplierAddress SA ON POL.Supplier_ID = SA.Supplier_ID
inner join PurchaseOrderHeader POH ON POH.PurchaseOrder_ID = POL.PurchaseOrder_ID
where Product_ID = curPO.Product_ID
and SA.AddressType = '1801') -
(select sum(<ReceiveQuantityCalculation>)
from PurchaseOrderLine POL
inner join SupplierAddress SA ON POL.Supplier_ID = SA.Supplier_ID
inner join PurchaseOrderHeader POH ON POH.PurchaseOrder_ID = POL.PurchaseOrder_ID
where Product_ID = curPO.Product_ID
and SA.AddressType = '1801')
fetch next from curPO
end
close curPO
deallocate curPO
Maybe you need something like that:
update DataBaseName..TableName
set ColumnName = value
where current of your_cursor_name;
Here's an example to calculate one column based upon values from two others (note, this could be done during the original table select). This example can be copy / pasted into an SSMS query window to be run without the need for any editing.
DECLARE #cust_id INT = 2, #dynamic_val NVARCHAR(40), #val_a INT, #val_b INT
DECLARE #tbl_invoice table(Cust_ID INT, Cust_Fees INT, Cust_Tax INT)
INSERT #tbl_invoice ( Cust_ID, Cust_Fees, Cust_Tax ) SELECT 1, 111, 11
INSERT #tbl_invoice ( Cust_ID, Cust_Fees, Cust_Tax ) SELECT 2, 222, 22
INSERT #tbl_invoice ( Cust_ID, Cust_Fees, Cust_Tax ) SELECT 3, 333, 33
DECLARE #TblCust TABLE
(
Rec_ID INT
, Val_A INT
, Val_B INT
, Dynamic_Val NVARCHAR(40)
, PRIMARY KEY NONCLUSTERED (Rec_ID)
)
INSERT #TblCust(Rec_ID, Val_A, Val_B, Dynamic_Val)
SELECT Rec_ID = Cust_ID, Val_A = Cust_Fees, Val_B = Cust_Tax, NULL
FROM #tbl_invoice
DECLARE cursor_cust CURSOR FOR
SELECT Rec_ID, Val_A, Val_B, Dynamic_Val
FROM #TblCust
WHERE Rec_ID <> #cust_id
FOR UPDATE OF Dynamic_Val;
OPEN cursor_cust;
FETCH NEXT FROM cursor_cust INTO #cust_id, #val_a, #val_b, #dynamic_val;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #TblCust
SET Dynamic_Val = N'#c = "' + LTRIM(STR((#val_a + #val_b), 40)) + N'"'
WHERE CURRENT OF cursor_cust
FETCH NEXT FROM cursor_cust INTO #cust_id, #val_a, #val_b, #dynamic_val;
END
CLOSE cursor_cust
DEALLOCATE cursor_cust
SELECT * FROM #TblCust