Must Declare Scalar - sql

I have three separate table variables in my Function,
1 of them is not giving me any errors, the other two are,
I haven't found anything Different Syntax-wise between them, but maybe I need more caffeine.
the error I am receiving is
Must declare the scalar variable "#DispoTable".
DECLARE #CIDdisp INT
DECLARE #DispoTable TABLE
(
CaseID INT,
Code INT,
Description VARCHAR(150)
)
--Gather Data From filter
SELECT #CIDdisp = CaseID, #Code = Code, #Description = Description
FROM fnRecidFilter3(#CaseID,01,01)
-- Insert into Temp table
INSERT INTO #DispoTable (CaseID, Code, Description)
VALUES (#CIDdisp, #Code, #Description)
-- Merge the Temp Table with RecidReport Table
INSERT INTO RecidReport(Code, Description)
SELECT Code, Description
FROM #DispoTable
WHERE (#DispoTable.CaseID) = CaseID
is there something that I am missing?

You can't say:
WHERE (#DispoTable.CaseID) = CaseID
Instead you need to use an alias:
FROM #DispoTable AS d
WHERE d.CaseID = CaseID
But this clause makes no sense anyway. Did you mean to use a variable here? Perhaps:
FROM #DispoTable AS d
WHERE d.CaseID = #CIDdisp
?

Related

SQL Merge not inserting new row

I am trying to use T-SQL Merge to check for the existence of records and update, if not then insert.
The update works fine, but the insert is not working.
Any and all help on this would be gratefully received.
DECLARE
#OperatorID INT = 2,
#CurrentCalendarView VARCHAR(50) = 'month';
WITH CTE AS
(
SELECT *
FROM dbo.OperatorOption
WHERE OperatorID = #OperatorID
)
MERGE INTO OperatorOption AS T
USING CTE S ON T.OperatorID = S.OperatorID
WHEN MATCHED THEN
UPDATE
SET T.CurrentCalendarView = #CurrentCalendarView
WHEN NOT MATCHED BY TARGET THEN
INSERT (OperatorID, PrescriptionPrintingAccountID, CurrentCalendarView)
VALUES (#OperatorID, NULL, #CurrentCalendarView);
When would a row Selected from OperatorOption not already exist in OperatorOption?
If you're saying this code does not insert - you're right it doesn't because the row has to be there to begin with (in which case it won't insert), or the row is not there to begin with, in which case there is nothing in the source dataset to insert.
Does
SELECT *
FROM dbo.OperatorOption
WHERE OperatorID = #OperatorID
return anything or not?
This does not work the way you think it does. There is nothing in the source CTE.
The answer to 'was a blank dataset missing from the target' is 'No' so nothing is inserted
To do this operation, I use this construct:
INSERT INTO dbo.OperatorOption
(OperatorID, PrescriptionPrintingAccountID, CurrentCalendarView)
SELECT #OperatorID, NULL, #CurrentCalendarView
WHERE NOT EXISTS (
SELECT * FROM dbo.OperatorOption
WHERE OperatorID = #OperatorID
)
It does not matter you are inserting values as variables. It thinks there is nothing to insert.
You need to produce data that does not match.
Like this:
DECLARE #OperatorID INT = 3, #CurrentCalendarView VARCHAR(50) = 'month';
declare #t table (operatorID int, CurrentCalendarView varchar(50));
insert into #t values (2, 'year');
MERGE #t AS TARGET
USING (SELECT #OperatorID, #CurrentCalendarView) AS source (operatorID, CurrentCalendarView)
on (TARGET.operatorID = Source.operatorID)
WHEN MATCHED THEN
UPDATE SET TARGET.CurrentCalendarView = #CurrentCalendarView
WHEN NOT MATCHED BY TARGET THEN
INSERT (OperatorID, CurrentCalendarView)
VALUES (source.OperatorID, source.CurrentCalendarView);
select * from #t
Insert probably isn't working because your source CTE does not produce any rows. Depending on how your table is organised, you might need to select from some other source, or use table valued constructor to produce source data.

How to store multiple values in a SQL Server variable

I want to store values from a SELECT statement into a variable which is capable of holding more than one value because my SELECT statement returns multiple values of type INT. This is how my SP looks like so far.
ALTER PROCEDURE "ESG"."SP_ADD"
AS
BEGIN
DECLARE #Id table(identifiers VARCHAR);
INSERT INTO #Id (identifiers) VALUES('axaa1aaa-aaaa-a5aa-aaaa-aa8aaaa9aaaa');
INSERT INTO #Id (identifiers) VALUES('bxbb1bbb-bbbb-b5bb-bbb4-bb8bbbb9bbbf');
DECLARE #tranID INT = (SELECT
DOCUMENT_SET_.DOCUMENT_SET_TRANSACTION_ID
FROM DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER IN (SELECT identifiers FROM #Id));
END
Variable #tranID should be a list or an array to hold the ids. Is it possible to do it SQL Server?
You can declare a variable of type table
DECLARE #tblTrans TABLE (
tranID INT
);
INSERT INTO #tblTrans
SELECT DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID
FROM ESG.DOCUMENT_SET_TRANSACTION
WHERE DOCUMENT_SET_TRANSACTION.IDENTIFIER
IN (SELECT identifiers FROM #envelopeId);
Depending on what you want to do with the values after this, you could declare a cursor to loop through them or select straight from the variable.
You could also look into using a temporary table depending on what scope you need.
Try this, only take the firs row of example. Do u try this?
select DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID,
(STUFF((SELECT '-' + convert(varchar(max),DOCUMENT_SET_TRANSACTION.DOCUMENT_SET_TRANSACTION_ID)
FROM ESG.DOCUMENT_SET_TRANSACTION
FOR XML PATH ('')), 1, 2, '')) AS example
FROM ESG.DOCUMENT_SET_TRANSACTION

Scalar Variable error using var Table but not Temp Table

I am stumped with this one. I have the following code it works fine up to the point of the last #POC_XLATE in the update statement and then I get the error MUST DECLARE SCALAR VARIABLE.
If I change the table to a temp table the code works fine. I have tried moving the select statement to the end of the code, that didn't work. Hope someone has some suggestion on why it is doing this. Thanks in advance.
declare #POC_XLATE as TABLE(
POC_XLATE_ID int NULL,
TAR_ID int NULL,
POC_USERID varchar(50) NULL,
ACTION_DATE datetime NULL
)
insert into #POC_XLATE(POC_XLATE_ID, TAR_ID, POC_USERID, ACTION_DATE)
select * from POC_XLATE
where POC_XLATE.ACTION_DATE is null
select * from #POC_XLATE
update #POC_XLATE
set ACTION_DATE = TAR_DATA.OPEN_DATE
from TAR_DATA
where #POC_XLATE.TAR_ID = TAR_DATA.TAR_ID
A column alias cannot start with a #. That is the sign for a declared scalar variable. So, use table aliases:
update p
set ACTION_DATE = td.OPEN_DATE
from #POC_XLATE p JOIN
TAR_DATA td
on p.TAR_ID = td.TAR_ID ;
But why you would write the query in two steps?
insert into #POC_XLATE(POC_XLATE_ID, TAR_ID, POC_USERID, ACTION_DATE)
select p.POC_XLATE_ID, p.TAR_ID, p.POC_USERID, td.OPEN_DATE
from POC_XLATE p left join
TAR_DATA td
on p.TAR_ID = td.TAR_ID
where p.ACTION_DATE is null;
One step is much cleaner than two.

SQL Merge Statement - Output into a scalar variable (SQL Server)

I'm getting my head around the MERGE statement in SQL server. I generally use it to insert/update a single row, which I realise isn't the only use, but it's something I seem to do quite often.
But what happens if you want to insert a value of 1, or update to increment the value and output the incremented value eg:
CREATE TABLE [Counter] (
[Key] VARCHAR(255) NOT NULL PRIMARY KEY,
[Value] INT NOT NULL
);
DECLARE #paramKey VARCHAR(255);
SET #paramKey = 'String';
MERGE [Counter] AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1);
-- but now I want the new value!
Is there a way of doing this? I notice the output clause in https://msdn.microsoft.com/en-gb/library/bb510625.aspx but it doesn't seem to work with scalars (I could output to a single row-ed table variable but that seems wrong):
-- using table variables but seems
DECLARE #paramKey VARCHAR(255), #value int;
SET #paramKey = 'String'
DECLARE #Tab table (
[Value] INT
)
MERGE Counter AS targt
USING (Values(#paramKey)) AS source ([Key])
ON (targt.[Key] = source.[Key])
WHEN MATCHED THEN
UPDATE SET Value = Value +1
WHEN NOT MATCHED THEN
INSERT ([Key], Value)
VALUES (source.[Key], 1)
OUTPUT inserted.[Value] INTO #Tab;
-- can now use #Tab as a single rowed table variable
Is there a better option?

SQL Delete Where Not In

I have a relation mapping table like this:
attributeid bigint
productid bigint
To clean relations that are not used any more, I want to delete all recors where productid = x and attributeid not in (#includedIds), like the following example:
#attributetypeid bigint,
#productid bigint,
#includedids varchar(MAX)
DELETE FROM reltable
WHERE productid = #productid AND
attributetypeid = #attributetypeid AND
attributeid NOT IN (#includedids);
When running the SQL with the includedids param containing more than 1 id - like this: 25,26 - I get a SqlException saying:
Error converting data type varchar to bigint.
And that is of course due to the , in that varchar(max) param...
How should I construct my delete statement to make it work?
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[ListToTable] (
/*
FUNCTION ListToTable
Usage: select entry from listtotable('abc,def,ghi') order by entry desc
PURPOSE: Takes a comma-delimited list as a parameter and returns the values of that list into a table variable.
*/
#mylist varchar(8000)
)
RETURNS #ListTable TABLE (
seqid int not null,
entry varchar(255) not null)
AS
BEGIN
DECLARE
#this varchar(255),
#rest varchar(8000),
#pos int,
#seqid int
SET #this = ' '
SET #seqid = 1
SET #rest = #mylist
SET #pos = PATINDEX('%,%', #rest)
WHILE (#pos > 0)
BEGIN
set #this=substring(#rest,1,#pos-1)
set #rest=substring(#rest,#pos+1,len(#rest)-#pos)
INSERT INTO #ListTable (seqid,entry) VALUES (#seqid,#this)
SET #pos= PATINDEX('%,%', #rest)
SET #seqid=#seqid+1
END
set #this=#rest
INSERT INTO #ListTable (seqid,entry) VALUES (#seqid,#this)
RETURN
END
Run that script in your SQL Server database to create the function ListToTable. Now, you can rewrite your query like so:
#attributetypeid bigint,
#productid bigint,
#includedids varchar(MAX)
DELETE FROM reltable
WHERE productid = #productid AND
attributetypeid = #attributetypeid AND
attributeid NOT IN (SELECT entry FROM ListToTable(#includedids));
Where #includedids is a comma delimited list that you provide. I use this function all the time when working with lists. Keep in mind this function does not necessarily sanitize your inputs, it just looks for character data in a comma delimited list and puts each element into a record. Hope this helps.
Joel Spolsky answered a very similar question here: Parameterize an SQL IN clause
You could try something similar, making sure to cast your attributetypeid as a varchar.
You can't pass a list as an parameter (AFAIK).
Can you rewrite the sql to use a subquery, something like this:
delete from reltable
WHERE productid = #productid AND
attributetypeid = #attributetypeid AND
attributeid NOT IN (select id from ... where ... );
?
That comma delimited list can be sent to a user defined function which will return it as a simple table. That table can then be queried by your NOT IN.
If you need the fn I can provide.. It's been about 5 yrs since I used sql much and I'll have to dust off that section of my brain..
Erland has the definitive guide for dealing with lists to table in SQL 2005, SQL 2008 gives you table based params.
On a side note I would avoid a NOT IN pattern for large lists, cause it does not scale, instead look at using left joins.