SET more than 1 row output into 1 variable - sql

I am wanting to be able to save more than just 1 output from a SELECT query in a single variable.
Currently I am gathering my needed data like so:
DECLARE #something1 VARCHAR(MAX)
DECLARE #something2 VARCHAR(MAX)
DECLARE #something3 VARCHAR(MAX)
SET #something1 = (
SELECT
Custom AS 'XXL Format'
FROM
tblData
WHERE
ID = 1);
SET #something2 = (
SELECT
Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format'
FROM
tblData
WHERE
ID = 1)
SET #something3 = (
SELECT
tbl1.paper,
tbl2.type
FROM
tblData AS tbl1
JOIN tblData2 tbl2
ON tbl1.ID = tbl2.ID
WHERE
ID = 1);
I have the following demo that shows what I am wanting to do
DECLARE #tester VARCHAR(MAX)
SET #tester = (
SELECT
tbl1.Custom AS 'XXL Format',
tbl1.Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format'
tbl1.paper,
tbl2.type
FROM
tblData AS tbl1
JOIN tblData2 tbl2
ON tbl1.ID = tbl2.ID
WHERE
ID = 1);
I get the error of:
Only one expression can be specified in the select list when
the subquery is not introduced with EXISTS
Both demos can be found here
I have tried to set the variable to "table" and store the data like that but that also does not seem to work correctly [I'm sure I am doing something wrong - that may be the answer to this question I'm asking]
How can I just use 1 variable for all that the above query outputs?

Your error is that the subquery returned more than one value. You can use top if you don't care which value gets assigned:
SET #tester = (SELECT TOP (1) description FROM ForgeRock);

You have to return only one value you can try top or limit like SET #tester = (SELECT TOP 1 description FROM ForgeRock); or SET #tester = (SELECT description FROM ForgeRock LIMIT 1);

So I guess I was correct with the set the variable to a temp "table". I finally just now got it to work for my needs!
DECLARE #tmpTbl table (_xml, _parsedXML, _paper, _type)
INSERT INTO #tmpTbl
SELECT
tbl1.Custom AS 'XML Format',
tbl1.Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format',
tbl1.paper,
tbl2.type
FROM
tblData AS tbl1
JOIN tblData2 AS tbl2
ON tbl1.ID = tbl2.ID
WHERE
ID = 1;
DECLARE #something1 VARCHAR(MAX) = (SELECT _xml FROM #tmpTbl);
DECLARE #something2 VARCHAR(MAX) = (SELECT _parsedXML FROM #tmpTbl);
DECLARE #something3 VARCHAR(MAX) = (SELECT _paper FROM #tmpTbl);
DECLARE #something4 VARCHAR(MAX) = (SELECT _type FROM #tmpTbl);
DELETE FROM #tmpTbl --Not really needed but nice to be offical :)
This above stores the values into one place. Although its not inside 1 variable I guess having to create a temp table isn't all that bad for the database/performance...

Related

Finding row until condition is met

This is my table:
PackingNr
SerienNr
PN185971
PN185972
PN185972
PN185974
PN185974
PN185978
PN185978
R005478
PN185968
R000547
PN185725
R004987
As an input I get PackingNr and I need to select SerienNr which is like Rxxxxx not PNxxxxx.
So for example, if I have input PN175971, I need to get SerienNr = R005478.
How can I do this inside of select query? I tried CASE but this won't work as I don't know how many times I have to go again.
My select query is selecting also other columns from different tables.
SELECT
... ,
CASE
WHEN PSPD.SerienNr LIKE '%PN%'
THEN
(SELECT SerienNr FROM PSAPacking_Det
WHERE PSAPacking_Det.PackingNr = PSPD.SerienNr)
ELSE PSPD.SerienNr
END AS SerienNr
...
FROM
PSAPacking PSPD
JOIN
...
WHERE
PSPD.PackingNr = 'PN185971'
You need a recursive CTE. Something like this:
WITH cte AS (
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
WHERE t..PackingNr = 'YourValueHere'
UNION ALL
SELECT t.PackingNr, t.SerienNr
FROM YourTable t
JOIN cte ON cte.SerienNr = t.PackingNr
)
SELECT TOP (1)
*
FROM cte
WHERE cte.SerienNr LIKE 'R%';
try this
declare #var2 varchar(max) = 'PN185971' --PUT YOUR INPUT HERE
declare #var1 varchar(max);
while(#var2 not like 'R%')
begin
set #var1 = #var2
set #var2 = (select max(SerienNr) from PSAPacking where PackingNr = #var1)
end
select #var2
if it doesn't find the value starting with R it returns null

Can we create a view after a script from a variable?

I would like to create a view at the end of the following request.
I know that 'create view' must be the first statement in a query batch. My problem is that for this query i must use a variable (#listOfIDRUB).
This variable is only fill correctly at the end of my little script.
I also have tried to create the view before my first declaration but it created a problem with "DECLARE".
So is it possible to create a view easily from the result of my script or i have to do something else ?
DECLARE #CounterResId int;
DECLARE #lePath varchar(255);
DECLARE #listOfIDRUB TABLE (EXTERNALREFERENCE uniqueidentifier, ID varchar(255), DOCID varchar(255) );
DECLARE #Max int;
SET #lePath = '';
SET #CounterResId = 1;
SET #Max = (SELECT COUNT(*) FROM SYNTHETIC..EXTRANET_PURGE WHERE TYPE_SUPPR = 'ResId')
WHILE (#CounterResId <= #Max )
BEGIN;
set #lePath =
(select tmp.lePath from
(
select row_number() over(order by path)as NumLigne, CONCAT(path, '%' ) as lePath from RUBRIQUE
WHERE MODELE = 'CAEEE64D-2B00-44EF-AA11-6B72ABD9FE38'
and CODE in (SELECT ID FROM SYNTHETIC..EXTRANET_PURGE where TYPE_SUPPR='ResId')
) tmp
WHERE tmp.NumLigne = #CounterResId)
INSERT INTO #listOfIDRUB(EXTERNALREFERENCE, ID, DOCID)
SELECT SEC.EXTERNALREFERENCE , SEC.ID, SEC.DOCUMENTID
FROM WEBACCESS_FRONT..SECTIONS sec
inner join rubrique rub ON rub.ID_RUBRIQUE = sec.EXTERNALREFERENCE
inner join template_tree_item tti ON tti.id_template_tree_item = rub.modele
inner join template t ON t.id_template = tti.template
WHERE t.CODE IN (SELECT TEMPLATE_CODE from SYNTHETIC..EasyFlowEngineListTemplateCode)
and rub.path like #lePath
print #CounterResId;
print #lePath;
set #CounterResId = #CounterResId + 1;
END;
select * from #listOfIDRUB;
Instead of select * from #listOfIDRUB
i wanted create view test as select * from listOfIDRUB
I have also tried create view test as (all my request)
Whenever you ask something about SQL please state your RDBMS (product and version). The answers are highly depending on this...
From your code I assume this is SQL Server.
So to your question: No, a VIEW must be "inlineable" (single-statement or "ad-hoc") statement.
You might think about a multi-statement UDF, but this is in almost all cases a bad thing (bad performance). Only go this way, if your result table will consist of rather few rows!
Without knowing your tables this is rather blind walking, but you might try this (add parameters, if you can transfer external operations (e.g. filtering) into the function):
CREATE FUNCTION dbo.MyFunction()
RETURNS #listOfIDRUB TABLE (EXTERNALREFERENCE uniqueidentifier, ID varchar(255), DOCID varchar(255) )
AS
BEGIN
DECLARE #CounterResId int;
DECLARE #lePath varchar(255);
DECLARE #Max int;
SET #lePath = '';
SET #CounterResId = 1;
SET #Max = (SELECT COUNT(*) FROM SYNTHETIC..EXTRANET_PURGE WHERE TYPE_SUPPR = 'ResId')
WHILE (#CounterResId <= #Max )
BEGIN;
set #lePath =
(select tmp.lePath from
(
select row_number() over(order by path)as NumLigne, CONCAT(path, '%' ) as lePath from RUBRIQUE
WHERE MODELE = 'CAEEE64D-2B00-44EF-AA11-6B72ABD9FE38'
and CODE in (SELECT ID FROM SYNTHETIC..EXTRANET_PURGE where TYPE_SUPPR='ResId')
) tmp
WHERE tmp.NumLigne = #CounterResId)
INSERT INTO #listOfIDRUB(EXTERNALREFERENCE, ID, DOCID)
SELECT SEC.EXTERNALREFERENCE , SEC.ID, SEC.DOCUMENTID
FROM WEBACCESS_FRONT..SECTIONS sec
inner join rubrique rub ON rub.ID_RUBRIQUE = sec.EXTERNALREFERENCE
inner join template_tree_item tti ON tti.id_template_tree_item = rub.modele
inner join template t ON t.id_template = tti.template
WHERE t.CODE IN (SELECT TEMPLATE_CODE from SYNTHETIC..EasyFlowEngineListTemplateCode)
and rub.path like #lePath
--print #CounterResId;
--print #lePath;
set #CounterResId = #CounterResId + 1;
END;
RETURN;
END
You can call it like this (very similar to a VIEW)
SELECT * FROM dbo.MyFunction();
And you might even use it in joins...
And last but not least I'm quite sure, that one could solve this without declares and a loop too...

Pass in list of parameters for LIKE query into stored procedure

I have a list of items that I would like to query on. The problem is that the number of items in the list is not constant. For example
select * from table1 where
field1 like #value1 + '%' OR
field1 like #value2 + '%'
I would like to pass value1, value2, etc into the stored procedure as a comma delimited string or something similar.
If you stored the values one per row in a table variable you could simply JOIN, or better, use WHERE EXISTS:
SELECT DISTINCT a.*
FROM Table1 a
WHERE EXISTS (SELECT 1
FROM #Table2 b
WHERE a.field1 like b.value + '%')
Here is a way you can pass a CSV to a stored proc, convert it to XML and use it in a join in your select.
Function to convert CSV to XML:
create function udf_CsvToXML(#Csv as varchar(8000),#Delim as varchar(15)=',')
returns xml
as
begin
declare #xml as xml = CAST('<XML>'+('<X>'+REPLACE(#Csv,#Delim,'</X><X>')+'</X></XML>') AS XML)
return #xml
end
Put the following in a stored proc, #Titles being a parameter instead of a declare:
declare #Titles varchar(8000) = NULL
SET #Titles = ISNULL(#Titles, 'ALL')
DECLARE #TitlesXML as XML
if upper(#Titles) = 'ALL'
SET #TitlesXML = (select distinct Title as X from LegalConfiguration for xml path(''), root('XML'))
else
SET #TitlesXML = dbo.udf_CsvToXML(#Titles,',')
select Title
from MonthlyTitlePerformance p
join (SELECT N.value('.[1]', 'varchar(25)') as value FROM #TitlesXML.nodes('/XML/X') as T(N)) tt
on tt.value = p.Title

Modifying XML Column with Select Query

I have a SQL Server table with a XML column which got information in. I want to select whole ID's from this table and modify my another xml column.
My query is;
declare #name nvarchar(max);
set #name = 'mark';
update table1
set table1.Information1.modify('insert <s n="' + cast((select cast(table2.Information2 as varchar(100))
from table2
where table2.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1) as varchar(400)) + '"/> into (/r)[1]') where table1.Name = #name;
I'm getting
Msg 8172, Level 16, State 1, Line 5
The argument 1 of the XML data type method "modify" must be a string literal.
Any help would be nice.
Are you sure you want to put the whole xml into attribute of Information1, like this:
declare #name nvarchar(max), #data xml
select #name = 'mark'
select cast(Information2 as varchar(100)) as n
from table2 as t
where t.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1
for xml raw('s')
update table1 set Information1.modify('insert sql:variable("#data") into (/r)[1]')
sql fiddle demo
Much as you are doing with the filtering, you need to use sql:variable. You can't build up a string inside a .modify function.
declare #newData xml
select #newData = '<s n="' +
cast(table2.Information2 as varchar(100))
+ '"/>'
from table2
where table2.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1
update table1 set Information1.modify('insert sql:variable("#newData") into (/r)[1]')

SQL WHERE ... IN clause with possibly null parameter

I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database.
I hope my question is clear enough. Here is my query below.
BEGIN
DECLARE #elements nvarchar(30)
DECLARE #jobtype_id INT
DECLARE #edu_id nvarchar(30)
DECLARE #categories nvarchar(30)
DECLARE #full_part bit
DECLARE #in_demand bit
DECLARE #lang char(2)
SET #jobtype_id = null
SET #lang = 'en'
SET #full_part = null -- full = 1, part = 0
SET #elements = '1,2,3'
SET #categories = '1,2,3'
SET #edu_id = '3,4,5'
select
jobs.name_en,
parttime.fulltime_only,
jc.cat_id category,
je.element_id elem,
jt.name_en jobtype,
jobs.edu_id minEdu,
education.name_en edu
from jobs
left join job_categories jc
on (jobs.job_id = jc.job_id)
left join job_elements je
on (jobs.job_id = je.job_id)
left join job_type jt
on (jobs.jobtype_id = jt.jobtype_id)
left join education
on (jobs.edu_id = education.edu_id)
left join
(select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime
on jobs.job_id = parttime.job_id
where [disabled] = 0
and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id)
and fulltime_only = isnull(#full_part,fulltime_only)
-- each of the following clauses should be validated to see if the parameter is null
-- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by
-- the field evaluated: ie if #elements is null, je.element_id in (je.element_id)
and je.element_id IN (SELECT * FROM ListToInt(#elements,','))
and jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))
and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,','))
order by case when #lang='fr' then jobs.name_fr else jobs.name_en end;
END
Something like
and (#elements IS NULL OR je.element_id IN
(SELECT * FROM ListToInt(#elements,',')))
and (#categories IS NULL OR
jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')))
....
should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL
that way for each one
Have you tried explicitly comparing to NULL?
and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,','))
And so on.