Assigning select results into variable in stored procedure in mssql? - sql-server

I have the following select:
SELECT School_Type,COUNT(ID) from Schools where City_ID = 1 group by School_Type
I get results:
10 | 3
20 | 4
30 | 14
I want to put results that are:
type 10 to variable #ElementarySchools
type 20 to variable #HighSchools
type 30 to variable #ProfessionalSchools
and get this result back from the Stored Procedure.
How do I do this ?

something like this? :)
declare #val varchar(max) = ''
select #val = #val + rtrim(foryear) + ' | ' + RTRIM( COUNT(*)) + ',' from mytable
group by ForYear
select #val

Using a table variable like this:
declare #tmp table (School_Type int, School_Count int)
insert into #tmp
SELECT School_Type,COUNT(ID) from Schools where City_ID = 1 group by School_Type
select #ElementarySchools=School_Count from #tmp where School_Type=10
select #HighSchools=School_Count from #tmp where School_Type=20
select #ProfessionalSchools=School_Count from #tmp where School_Type=30

Related

Multiple tables in the where clause SQL

I have 2 tables:-
Table_1
GetID UnitID
1 1,2,3
2 4,5
3 5,6
4 6
Table_2
ID UnitID UserID
1 1 1
1 2 1
1 3 1
1 4 1
1 5 2
1 6 3
I want the 'GetID' based on 'UserID'.
Let me explain you with an example.
For e.g.
I want all the GetID where UserID is 1.
The result set should be 1 and 2. 2 is included because one of the Units of 2 has UserID 1.
I want all the GetID where UserID is 2
The result set should be 2 and 3. 2 is included because one of Units of 2 has UserID 2.
I want to achieve this.
Thank you in Advance.
You can try a query like this:
See live demo
select
distinct userid,getid
from Table_1 t1
join Table_2 t2
on t1.unitId+',' like '%' +cast(t2.unitid as varchar(max))+',%'
and t2.userid=1
The query for this will be relatively ugly, because you made the mistake of storing CSV data in the UnitID column (or maybe someone else did and you are stuck with it).
SELECT DISTINCT
t1.GetID
FROM Table_1 t1
INNER JOIN Table_2 t2
ON ',' + t1.UnitID + ',' LIKE '%,' + CONVERT(varchar(10), t2.UnitID) + ',%'
WHERE
t2.UserID = 1;
Demo
To understand the join trick being used here, for the first row of Table_1 we are comparing ,1,2,3, against other single UnitID values from Table_2, e.g. %,1,%. Hopefully it is clear that my logic would match a single UnitID value in the CSV string in any position, including the first and last.
But a much better long term approach would be to separate those CSV values across separate records. Then, in addition to requiring a much simpler query, you could take advantage of things like indices.
try this:
declare #Table_1 table(GetID INT, UnitId VARCHAR(10))
declare #Table_2 table(ID INT, UnitId INT,UserId INT)
INSERT INTO #Table_1
SELECT 1,'1,2,3'
union
SELECT 2,'4,5'
union
SELECT 3,'5,6'
union
SELECT 4,'6'
INSERT INTO #Table_2
SELECT 1,1,1
union
SELECT 1,2,1
union
SELECT 1,3,1
union
SELECT 1,4,1
union
SELECT 1,5,2
union
SELECT 1,6,3
declare #UserId INT = 2
DECLARE #UnitId VARCHAR(10)
SELECT #UnitId=COALESCE(#UnitId + ',', '') + CAST(UnitId AS VARCHAR(5)) from #Table_2 WHERE UserId=#UserId
select distinct t.GetId
from #Table_1 t
CROSS APPLY [dbo].[Split](UnitId,',') AS AA
CROSS APPLY [dbo].[Split](#UnitId,',') AS BB
WHERE AA.Value=BB.Value
Split Function:
CREATE FUNCTION [dbo].Split(#input AS Varchar(4000) )
RETURNS
#Result TABLE(Value BIGINT)
AS
BEGIN
DECLARE #str VARCHAR(20)
DECLARE #ind Int
IF(#input is not null)
BEGIN
SET #ind = CharIndex(',',#input)
WHILE #ind > 0
BEGIN
SET #str = SUBSTRING(#input,1,#ind-1)
SET #input = SUBSTRING(#input,#ind+1,LEN(#input)-#ind)
INSERT INTO #Result values (#str)
SET #ind = CharIndex(',',#input)
END
SET #str = #input
INSERT INTO #Result values (#str)
END
RETURN
END

count in dynamic name SQL Server

I create a stored procedure in SQL Server:
ALTER PROCEDURE [dbo].[testChildren]
#Parent INT
AS
BEGIN
SET NOCOUNT ON;
WITH EntityChildren AS
(
SELECT
nname, nodeid, level, ncode, nparent
FROM
GrpItm
WHERE
nodeid = #Parent
UNION ALL
SELECT
e.nname, e.nodeid, e.level, e.ncode, e.nparent
FROM
GrpItm e
INNER JOIN
EntityChildren e2 ON e.nparent = e2.nodeid
)
SELECT COUNT(Level) AS [level]
FROM EntityChildren
END
How can I make each count level in row and named the row by level value like this:
| level 1 | level 2 | level 3 |
+---------+---------+---------+
| 2 | 3 | 1 |
If you want something closer to...
level | count
-------+-------
1 | 2
2 | 3
3 | 1
Then it would just be something like...
SELECT
level,
COUNT(*) AS row_count
FROM
EntityChildren
GROUP BY
level
But that's simpler than what you're already accomplished, so I may be missing the point of your question and comment?
This is only regarding to #MatBailie answer. If you have a table like his, you can pivot your data and get it as you request.
Table Created with Levels and counts
You need a script to populate this table with the values you need
create table dbo.myt (levels int, counts int)
insert into dbo.myt
values
(1 , 2),
(2 , 3),
(3 , 1)
SQL Code
DECLARE #ALIASNAME nvarchar(50) = 'Levels'
DECLARE #Str NVARCHAR(MAX);
DECLARE #Str2 NVARCHAR(MAX);
SELECT #Str = STUFF(
(
SELECT DISTINCT
','+'[Levels'+cast(levels as nvarchar(50))+']'
FROM dbo.myt FOR XML PATH('')
), 1, 1, '');
PRINT #Str
SET #str2 = N'select * from (
select cast('''+#ALIASNAME+'''+ cast(Levels as nvarchar(50)) as nvarchar(50)) as Levels,counts,ROW_NUMBER() over(PARTITION by levels order by counts) as rn
from dbo.myt
)x
PIVOT
(Max(counts) FOR Levels in ('+#Str+')
) as p';
PRINT #Str2;
EXEC (#Str2);
Your Stored proc
ALTER PROCEDURE [dbo].[testChildren]
#Parent INT
AS
BEGIN
SET NOCOUNT ON;
WITH EntityChildren AS
(
SELECT
nname, nodeid, level, ncode, nparent
FROM
GrpItm
WHERE
nodeid = #Parent
UNION ALL
SELECT
e.nname, e.nodeid, e.level, e.ncode, e.nparent
FROM
GrpItm e
INNER JOIN
EntityChildren e2 ON e.nparent = e2.nodeid
)
INSERT INTO dbo.myt (Levels,Counts)
SELECT
level, COUNT(*) AS row_count
FROM
EntityChildren
GROUP BY level
/* INSERT PIVOT SCRIPT AND INSERT INTO A NEW TABLE */
END
Result

Pivot and concatenate values from column in SQL Server

I have table with these columns:
ID | Name | Value
------------------
1 | Test1 | 0
2 | Test2 | 1
3 | Test3 | 0
4 | Test4 | 0
5 | Test5 | 1
And I want to have pivoted and concatenated value column as string
01001
The below code will give the expected result:
SELECT #Result = #Result + CAST(VALUE AS VARCHAR)
FROM #TmpTestingTable
Or you can use the STUFF:
SELECT STUFF(
( SELECT CAST(VALUE AS VARCHAR)
FROM #TmpTestingTable
FOR XML PATH ('')
), 1, 0, '')
For sample, I inserted the columns into the temporary table and execute the code.
CREATE TABLE #TmpTestingTable (ID INT, Name VARCHAR (20), Value INT)
INSERT INTO #TmpTestingTable (ID, Name, Value) VALUES
(1 , 'Test1' , 0),
(2 , 'Test2' , 1),
(3 , 'Test3' , 0),
(4 , 'Test4' , 0),
(5 , 'Test5' , 1)
DECLARE #Result AS VARCHAR (100) = '';
-- using variable approach
SELECT #Result = #Result + CAST(VALUE AS VARCHAR)
FROM #TmpTestingTable
SELECT #Result
-- using STUFF approach
SELECT STUFF(
( SELECT CAST(VALUE AS VARCHAR)
FROM #TmpTestingTable
FOR XML PATH ('')
), 1, 0, '')
DROP TABLE #TmpTestingTable
Use FOR XML to concatinate. It is important that you also include an ORDER BY. Otherwise you have no control of the order of the values and you risk an arbitrary order.
SELECT
(SELECT CAST([VALUE] AS CHAR(1))
FROM yourtable
ORDER BY ID
FOR XML PATH ('')
)
SELECT GROUP_CONCAT(Value SEPARATOR '') FROM Table
EDIT:
Not working on SQL Server. Have a look at Simulating group_concat MySQL function in Microsoft SQL Server 2005? to try to make it work

I want to return the same item twice in SQL Server

A very simple question. Couldn't find something similar here (maybe I didn't use the right wording. Sorry in advance).
I have a table:
| ID | FullName |
-------------------
| 1 | Frank Owa |
| 2 | Gail Sorbe |
I wish the query to display all the users that contains the string either 'ran' or 'wa'.
And that includes duplicates.
So, what I expect to get is:
|ID | FullName |
-----------------
|1 | Frank Owa |
|1 | Frank Owa |
Because Frank Owa has either 'ran' or 'wa'. And I wish to display it twice as a result.
But the query will display the result only once.
SELECT *
FROM Table
WHERE FullName LIKE '%ran%' OR FullName LIKE '%wa%'
What did I do wrong?...
Thanks
The query checks on an either-or basis - if a row meets any of the 2 conditions, it is included once and then the next row is checked. If you want it to appear twice on account of meeting 2 different conditions, you could use UNION ALL, like so:
SELECT *
FROM Table
WHERE FullName LIKE '%ran%'
UNION ALL
SELECT *
FROM Table
WHERE FullName LIKE '%wa%'
Use UNION ALL
SELECT * FROM TABLE WHERE FullName LIKE '%ran%'
UNION ALL
SELECT * FROM TABLE WHERE FullName LIKE '%wa%'
You can do a Union All between queries that fetch names containing 'ran' and and query that fetches 'wa'.
SELECT * FROM Table WHERE FullName LIKE '%ran%'
UNION ALL
SELECT * FROM Table WHERE FullName LIKE'%wa%'
Since the condition is dynamic and you cannot write UNION ALL every time you have to do it dynamically.
You sample table
SELECT * INTO #TABLE
FROM
(
SELECT 1 Id, 'Frank Owa' FullName
UNION ALL
SELECT 2,'Gail Sorbe'
)TAB
Now you need to split the values and insert into a temparery table.
DECLARE #Split VARCHAR(1000);
SET #Split = 'ran,wa';
DECLARE #x XML;
SET #x = '<r>' + REPLACE((SELECT #Split FOR XML PATH('')), ',', '</r><r>') + '</r>';
SELECT ROW_NUMBER() OVER(ORDER BY y.XmlCol.value('(text())[1]', 'VARCHAR(1000)'))RNO,
y.XmlCol.value('(text())[1]', 'VARCHAR(1000)') AS Value
INTO #TEMP
FROM #x.nodes('/r') y(XmlCol);
Now, the following code will write UNION ALL dynamically for you
DECLARE #I INT=1
DECLARE #COUNT INT
DECLARE #QRY NVARCHAR(MAX)
DECLARE #CONDITION NVARCHAR(MAX)
DECLARE #NAME NVARCHAR(MAX)
SELECT #COUNT=COUNT(*) FROM #TEMP
-- Loop will be executed for the number of parameters, ie, for your above example,
-- #COUNT will be 2.
WHILE(#I <= #COUNT)
BEGIN
-- Select ran on first loop wa on second loop etc
SELECT #NAME = Value FROM #TEMP WHERE RNO= #I
SET #CONDITION = 'SELECT * FROM #TABLE WHERE FullName LIKE ''%' + #NAME + '%'' UNION ALL '
SELECT #QRY = COALESCE(#QRY,'') + #CONDITION
SET #I=#I+1;
END
Now you need to remove last UNION ALL and execute the query dynamically
SELECT #QRY = LEFT(#QRY, LEN(#QRY)-9)
EXEC SP_EXECUTESQL #QRY
Here is the result

SQL - Move last 2 character to become first 2

I need move last 2 characters of string to become first 2, for example, "ABC PT" become "PT ABC".
Thanks for help.
DECLARE #String VARCHAR(100) = 'ABC PT'
SELECT RIGHT(#String, 2) + ' ' + LEFT(#String, LEN(#String) -2)
RESULT : PT ABC
You can use substring function.
for example :
select substring('ABC PT',len('ABC PT')-1,2)+' '+stuff('ABC PT',len('ABC PT')-1,2,'')
Query:
DECLARE #Str as nvarchar(10);
SET #Str = 'ABC PT';
SELECT RTRIM(RIGHT(#Str,2)+' '+SUBSTRING(#Str, 1 , LEN(#Str)-2))
Result:
PT ABC
below is the select statement, use it to update if you want to
c1 is the column name in the table test15.
If you have a variable then replace c1 with the variable name and remove the from clause.
select RIGHT(c1,2)+SUBSTRING(c1,1,len(c1)-2) from test15
CREATE TABLE #TEMP
(
ID INT IDENTITY(1,1) ,
NAME VARCHAR(50)
)
INSERT INTO #TEMP VALUES('PC1AB')
INSERT INTO #TEMP VALUES('PC2XY')
INSERT INTO #TEMP VALUES('PC3NA')
INSERT INTO #TEMP VALUES('PC3NAXBBNTEYE12')
SELECT SUBSTRING(NAME,LEN(NAME)-1,2)+LTRIM(LEFT(NAME,LEN(NAME)-2)) FROM #TEMP

Resources