Store query result in variable - sql-server

I have declared 6 variables in a stored procedure and I'd like to store a query result (which may bring up to 6 records) into each one of those variables. My query looks like this:
DECLARE
#Sib1 varchar(20),
#Sib2 varchar(20),
#Sib3 varchar(20),
#Sib4 varchar(20),
#Sib5 varchar(20),
#Sib6 varchar(20)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc
I'd like to put each one of the resulting SKU in each #SIB variables. if it only returns 1 result, I'd like to put null values into the rest of the #SIB variables.
Thanks.

You could insert the SKU's into a table variable, with an identity column. Then set the variables equal to the sku in the table based on the identity columns value.
DECLARE #Sib1 VARCHAR(20)
,#Sib2 VARCHAR(20)
,#Sib3 VARCHAR(20)
,#Sib4 VARCHAR(20)
,#Sib5 VARCHAR(20)
,#Sib6 VARCHAR(20);
DECLARE #TempTbl TABLE (
RowID INT IDENTITY
,SKU VARCHAR(20)
)
INSERT INTO #TempTbl (SKU)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc
SELECT #Sib1 = SKU
FROM #TempTbl
WHERE RowID = 1;
SELECT #Sib2 = SKU
FROM #TempTbl
WHERE RowID = 2;
SELECT #Sib3 = SKU
FROM #TempTbl
WHERE RowID = 3;
SELECT #Sib4 = SKU
FROM #TempTbl
WHERE RowID = 4;
SELECT #Sib5 = SKU
FROM #TempTbl
WHERE RowID = 5;
SELECT #Sib6 = SKU
FROM #TempTbl
WHERE RowID = 6;
EDIT
DECLARE #SQL VARCHAR(MAX);
SET #SQL = 'SELECT SKU, ..., sum(convert(INT, a.qty)) AS ' + #sib1 + ' FROM ...'
EXEC (#SQL);

Rather use a table variable like
DECLARE #MyTableVar table(
SKU int NOT NULL);
Then insert into it
insert into #MyTableVar(SKU)
select
PC.SKU
from
Product PC
where
Parent_code in (select
Parent_code
from
Product
where
SKU =12345)
and ParentFlag <> 'p'
and SKU <> 12345
order by Parent_Child_Priority desc;
Now you can use that #MyTableVar as you need. You don't need to declare N variable for N records.

Related

How to write this procedure to get auto-increment alphanumeric id in SQL Server?

Table structure is as follows:
CREATE TABLE tblContact
(
SrNo DECIMAL IDENTITY(1,1) NOT NULL,
InquiryId VARCHAR(10) PRIMARY KEY,
SenderName VARCHAR(50),
SenderEmail VARCHAR(200),
SenderSubject VARCHAR(50),
SenderMessage VARCHAR(MAX),
IsActive BIT DEFAULT(1),
IsDelete BIT DEFAULT(0),
CreatedOn DATETIME DEFAULT(GETDATE()),
CreatedBy VARCHAR(10),
UpdatedOn DATETIME,
UpdatedBy VARCHAR(10)
)
Procedure listing is as follows:
CREATE PROC Usp_GetNewInquiryId
AS
BEGIN
IF NOT EXISTS(SELECT InquiryId FROM JobPortal.dbo.tblContact)
DECLARE #PrefixValue VARCHAR(10) = 'INQ'
DECLARE #InitialValue DECIMAL(10) = 1001
SELECT InquiryId = #PrefixValue + CAST(ISNULL(MAX(InquiryId), #InitialValue) AS VARCHAR(10))
FROM JobPortal.dbo.tblContact
ELSE
/* here I want to eliminate the word 'INQ' from 'INQ1001' towards left side and do increment 1002 from 1001, lastly want to select INQ1002 and so on... */
SELECT TOP 1
InquiryId = #PrefixValue + CONVERT(VARCHAR(10), SUBSTRING(InquiryId, 4, 4)) + 1
FROM JobPortal.dbo.tblContact
ORDER BY InquiryId DESC
END
Desired Output:
If table is empty then InquiryId=INQ1001
Otherwise InquiryId=INQ1002
If you want to return the "next available" InquiryId for tblContact, I would do this:
CREATE PROCEDURE Usp_GetNewInquiryId
AS
BEGIN
IF NOT EXISTS (SELECT InquiryId FROM tblContact)
SELECT 'INQ1001'
ELSE
SELECT TOP 1 'INQ' + CONVERT(VARCHAR,CONVERT(INT,REPLACE(InquiryId,'INQ','')) + 1) FROM tblContact ORDER BY InquiryId DESC
END

How can I put a Transac SQL block into a function that I can reuse in Stored Procedures?

I have code to take the [Correct] column of a table with a particular QuestionId and make it it to a character string:
Here's the code that was suggested to me. It really just has one input which is the [QuestionUId] and one output which is a string looking like "001110" or "00111" or "111" etc.
-- I need to actually search by QuestionUId so I have this to get the QuestionId
DECLARE #QuestionId int;
SELECT #QuestionId = QuestionID
FROM dbo.question
Where QuestionUId = '87e6bbac-651f-4fdb-862b-412979f71847';
;WITH Partitioned AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY QuestionId ORDER BY AnswerId ASC) AS RowNumber
, COUNT(1) OVER (PARTITION BY QuestionId) AS ColumnCount
, CONVERT(VARCHAR(MAX), Correct) AS Correct
FROM
#Answers
WHERE
[QuestionId] = #QuestionId
),
Concatenated AS (
SELECT RowNumber, ColumnCount, Correct FROM Partitioned WHERE RowNumber = 1
UNION ALL
SELECT
P.RowNumber
, P.ColumnCount
, C.Correct + P.Correct AS Correct
FROM
Partitioned P
INNER JOIN Concatenated C
ON P.RowNumber = C.RowNumber + 1
)
SELECT
CONVERT(VARCHAR(20), Correct) AS Correct
FROM
Concatenated
WHERE
RowNumber = ColumnCount
The code works but I would like to make this code available so it can be used by more than one stored procedure.
Can someone tell me is there a way I can put this code into a function or should I just put it into another stored procedure and if so then how could I do that and how could I call it ?
FYI here's the tables that are used and some sample input and output data:
CREATE TABLE [dbo].[Question] (
[QuestionId] INT,
[QuestionUId] UNIQUEIDENTIFIER
)
CREATE TABLE [dbo].[Answer] (
[AnswerId] INT IDENTITY (1, 1) NOT NULL,
[QuestionId] INT NOT NULL,
[Correct] BIT NULL
);
AnswerId QuestionId Correct >>>>> needed a string "001"
19 8 0
20 8 0
21 8 1
AnswerId QuestionId Correct >>>>> needed a string "10"
22 9 1
23 9 0
As far as I understand your code returns a single varchar value. So you can create scalar function from it. It will look something like that:
CREATE FUNCTION dbo.MyFunc
(
#QuestionId int
)
RETURNS varchar(20)
AS
BEGIN
DECLARE #RetVal varchar(20)
-- I need to actually search by QuestionUId so I have this to get the QuestionId
;WITH Partitioned AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY QuestionId ORDER BY AnswerId ASC) AS RowNumber
, COUNT(1) OVER (PARTITION BY QuestionId) AS ColumnCount
, CONVERT(VARCHAR(MAX), Correct) AS Correct
FROM
#Answers
WHERE
[QuestionId] = #QuestionId
),
Concatenated AS (
SELECT RowNumber, ColumnCount, Correct FROM Partitioned WHERE RowNumber = 1
UNION ALL
SELECT
P.RowNumber
, P.ColumnCount
, C.Correct + P.Correct AS Correct
FROM
Partitioned P
INNER JOIN Concatenated C
ON P.RowNumber = C.RowNumber + 1
)
SELECT
#RetVal = CONVERT(VARCHAR(20), Correct) AS Correct
FROM
Concatenated
WHERE
RowNumber = ColumnCount
RETURN #RetVal
END
Then you call call it from any other T-SQL code (queries, procedures, other functions):
DECLARE #QuestionId int;
SELECT #QuestionId = QuestionID
FROM dbo.question
Where QuestionUId = '87e6bbac-651f-4fdb-862b-412979f71847';
SELECT dbo.MyFunc(#QuestionId)

Transform row in column in a table

I am trying to rotate the visualization of a table showing the lines as columns without any kind of aggregation.
Suppose I have this table
create table user
id int,
name nvarchar(100),
company nvarchar(100),
division nvarchar(100),
city nvarchar(100)
that can be retrieved with this select
select name,company division, city from user order by id
wich gives me this result
john Company1 division1 City1
Peter Company2 division2 City2
Mary Company3 division3 City3
.
.
but what I need is to show each line as a column and the first column with the name of the field like this
Name john Peter Mary ....
Company Company1 Company2 Company3 ....
Division division1 division2 division3 ....
City City1 City2 City3 ....
How can I accomplish this? I Tried using this unpivot
select col,value
from
(select cast(name as varchar) as name,
cast(Company as varchar) as company,
cast(Division as varchar) as division
cast(City as varchar) as city
from user) p
unpivot
(value for col in (name,company,division,city)) as unpvt
but this is what I got (Note: I want all the names in the same row)
name john
Company Company1
Division division1
City City1
name peter // this should be in the first row as a second column
Company Company2
Division division2
City City2
...
This is super ugly, but it's the only way I could figure out how to do what you want solely in SQL Server. If you copy and paste the code it should run and give you results and leave your database clean. I use a couple permanent tables to work around some dynamic sql scoping limitations, but I drop them both before it's done.
If Object_ID('tempdb..#userInfo') Is Not Null Drop Table #userInfo
Create Table #userInfo (id Int, name Varchar(100), company Varchar(100), division Varchar(100), city Varchar(100))
Insert #userInfo (id, name, company, division, city)
Values (1, 'john','company1', 'division1', 'city1'),
(2, 'peter','company2', 'division2', 'city2'),
(3, 'mary','company3', 'division3', 'city3'),
(4, 'timmy','company4', 'division4', 'city4'),
(5, 'nancy','company5', 'division5', 'city5'),
(6, 'james','company6', 'division6', 'city6'),
(7, 'brandon','company7', 'division7', 'city7'),
(8, 'jay','company8', 'division8', 'city8')
If Object_ID('tempdb..#unPivoted') Is Not Null Drop Table #unPivoted
Create Table #unPivoted (id Int, rid Int, col Varchar(100), value Varchar(100))
Insert #unPivoted
Select id, Row_Number() Over (Partition By id Order By value) As rID, col, value
From #userInfo p
Unpivot (value For col In (name, company, division, city)) As u
If Object_ID('dbo.TempQueryOutput') Is Not Null Drop Table dbo.TempQueryOutput
Select 1 As OrderCol,'City' As ColName Into dbo.TempQueryOutput
Union
Select 2,'Company'
Union
Select 3,'Division'
Union
Select 4,'Name'
Declare #sql Nvarchar(Max),
#maxID Int,
#loopIter Int = 1
Select #maxID = Max(id)
From #userInfo
While #loopIter <= #maxID
Begin
Set #sql = 'Select o.*, u.value As Col' + Convert(Nvarchar(100),#loopIter) + ' Into dbo.TempQueryTable
From dbo.TempQueryOutput o
Join #unPivoted u
On o.OrderCol = u.rid
And u.id = ' + Convert(Nvarchar(100),#loopIter)
Exec sp_executeSQL #sql
If Object_ID('dbo.TempQueryOutput') Is Not Null Drop Table dbo.TempQueryOutput
Select * Into dbo.TempQueryOutput
From dbo.TempQueryTable
If Object_ID('dbo.TempQueryTable') Is Not Null Drop Table dbo.TempQueryTable
Set #loopIter = #loopIter + 1
End
Update dbo.TempQueryOutput
Set OrderCol = Case
When ColName = 'Name' Then 1
When ColName = 'Company' Then 2
When ColName = 'Division' Then 3
When ColName = 'City' Then 4
End
Select *
From dbo.TempQueryOutput
Order By OrderCol
If Object_ID('dbo.TempQueryOutput') Is Not Null Drop Table dbo.TempQueryOutput

SQL simple break out by quantity

I would like to perform a simple break out by quantity in SQL.
I have as follows:
Table name : Products
product quantity
======= ========
Car 2
Bike 1
Results:
Car
Car
Bike
Thanks!
One solution is to join to a table of numbers. This can repeat the row quantity times. In T-SQL, a list of numbers can be generated with a recursive CTE:
; with Numbers as
(
select max(quantity) as nr
from YourTable
union all
select nr - 1
from Numbers
where nr > 1
)
select yt.product
from YourTable yt
join Numbers nr
on nr.nr <= yt.quantity
option (maxrecursion 0)
Live example at SQL Fiddle.
Here is a non-CTE answer to show why you should use the CTE :)
MAIN TABLE
DECLARE #table TABLE
(
ID INT IDENTITY,
Product VARCHAR(20),
Quantity INT
)
OUT TABLE
DECLARE #outtable TABLE
(
ID INT IDENTITY,
Product VARCHAR(20)
)
TEST DATA
INSERT INTO #table
(
Product,
Quantity
)
SELECT 'Car',
2
UNION ALL
SELECT 'Bike',
1
Main Query
DECLARE #counter INT,
#maxcounter INT,
#curproduct INT
SELECT TOP 1
#curproduct = id
FROM #table
WHILE EXISTS ( SELECT TOP 1
1
FROM #table
WHERE ID >= #curproduct )
BEGIN
SELECT #counter = 1,
#maxcounter = quantity
FROM #table
WHERE ID = #curproduct
WHILE #counter <= #maxcounter
BEGIN
INSERT INTO #outtable
(
Product
)
SELECT product
FROM #table
WHERE id = #curproduct
SET #counter = #counter + 1
END
SET #curproduct = #curproduct + 1
END
FINALLY
SELECT *
FROM #outtable

Can I use #table variable in SQL Server Report Builder?

Using SQL Server 2008 Reporting services:
I'm trying to write a report that displays some correlated data so I thought to use a #table variable like so
DECLARE #Results TABLE (Number int
,Name nvarchar(250)
,Total1 money
,Total2 money
)
insert into #Results(Number, Name, Total1)
select number, name, sum(total)
from table1
group by number, name
update #Results
set total2 = total
from
(select number, sum(total) from table2) s
where s.number = number
select from #results
However, Report Builder keeps asking to enter a value for the variable #Results. It this at all possible?
EDIT: As suggested by KM I've used a stored procedure to solve my immediate problem, but the original question still stands: can I use #table variables in Report Builder?
No.
ReportBuilder will
2nd guess you
treats #Results as a parameter
Put all of that in a stored procedure and have report builder call that procedure. If you have many rows to process you might be better off (performance wise) with a #temp table where you create a clustered primary key on Number (or would it be Number+Name, not sure of your example code).
EDIT
you could try to do everything in one SELECT and send that to report builder, this should be the fastest (no temp tables):
select
dt.number, dt.name, dt.total1, s.total2
from (select
number, name, sum(total) AS total1
from table1
group by number, name
) dt
LEFT OUTER JOIN (select
number, sum(total) AS total2
from table2
GROUP BY number --<<OP code didn't have this, but is it needed??
) s ON dt.number=s.number
I've seen this problem as well. It seems SQLRS is a bit case-sensitive. If you ensure that your table variable is declared and referenced everywhere with the same letter case, you will clear up the prompt for parameter.
You can use Table Variables in SSRS dataset query like in my code where I am adding needed "empty" records for keep group footer in fixed postion (sample use pubs database):
DECLARE #NumberOfLines INT
DECLARE #RowsToProcess INT
DECLARE #CurrentRow INT
DECLARE #CurRow INT
DECLARE #cntMax INT
DECLARE #NumberOfRecords INT
DECLARE #SelectedType char(12)
DECLARE #varTable TABLE (# int, type char(12), ord int)
DECLARE #table1 TABLE (type char(12), title varchar(80), ord int )
DECLARE #table2 TABLE (type char(12), title varchar(80), ord int )
INSERT INTO #varTable
SELECT count(type) as '#', type, count(type) FROM titles GROUP BY type ORDER BY type
SELECT #cntMax = max(#) from #varTable
INSERT into #table1 (type, title, ord) SELECT type, N'', 1 FROM titles
INSERT into #table2 (type, title, ord) SELECT type, title, 1 FROM titles
SET #CurrentRow = 0
SET #SelectedType = N''
SET #NumberOfLines = #RowsPerPage
SELECT #RowsToProcess = COUNT(*) from #varTable
WHILE #CurrentRow < #RowsToProcess
BEGIN
SET #CurrentRow = #CurrentRow + 1
SELECT TOP 1 #NumberOfRecords = ord, #SelectedType = type
FROM #varTable WHERE type > #SelectedType
SET #CurRow = 0
WHILE #CurRow < (#NumberOfLines - #NumberOfRecords % #NumberOfLines) % #NumberOfLines
BEGIN
SET #CurRow = #CurRow + 1
INSERT into #table2 (type, title, ord)
SELECT type, '' , 2
FROM #varTable WHERE type = #SelectedType
END
END
SELECT type, title FROM #table2 ORDER BY type ASC, ord ASC, title ASC
Why can't you just UNION the two resultsets?
How about using a table valued function rather than a stored proc?
It's possible, only declare your table with '##'. Example:
DECLARE ##results TABLE (Number int
,Name nvarchar(250)
,Total1 money
,Total2 money
)
insert into ##results (Number, Name, Total1)
select number, name, sum(total)
from table1
group by number, name
update ##results
set total2 = total
from
(select number, sum(total) from table2) s
where s.number = number
select * from ##results

Resources