Passing Value to parameter in stored procedure - sql

I have a list of value which is more than 500, and every time I have to pass those value to the below stored procedure. Will it be possible to call those value dynamically?
RDBMS: SQL Server 2014
small set of #value example below.
declare #valuetable table
(
value varchar(50)
)
insert #valuetable
select video union
select audio union
select hayward union
select abott union
select gsk
Code:
DECLARE #value VARCHAR(24) SET #value = 'video'
DECLARE #DAYS INT SET #DAYS = -30
SELECT * INTO #XTP1 FROM (
SELECT DISTINCT 'START' AS DTT, DATEADD(D,#DAYS,DATEACTIONED) AS DT FROM NEWREPORTS
WHERE value = #value
UNION
SELECT DISTINCT 'CHANGE' AS DTT, DATEACTIONED AS DT FROM NEWREPORTS
WHERE value = #value
)r
Thanks

So what you need to do is to add one column to #XTP1 to store the value name. Then you can do:
declare #valuetable table
(
value varchar(50)
)
insert #valuetable
select video union
select audio union
select hayward union
select abott union
select gsk
SELECT * INTO #XTP1 FROM (
SELECT DISTINCT v.value, 'START' AS DTT, DATEADD(D,#DAYS,DATEACTIONED) AS DT
FROM NEWREPORTS n INNER JOIN #valuetable v ON n.value = v.value
UNION
SELECT DISTINCT v.value, 'CHANGE' AS DTT, DATEACTIONED AS DT
FROM NEWREPORTS n INNER JOIN #valuetable v ON n.value = v.value
)r
Now you can retrieve everything from #XTP1 in one go. You will probably want to include "value" in your ORDER BY.

Related

Updating a field from an inner join - or default value on a miss

I'd like to figure out if this can be done in one step instead of two. Right now, I update every target field with a default value, then update again based on an inner join.
create table #tmp (buyer varchar(1000), contract_assignee varchar(1000), contract_assignee_address varchar(1000), lenderid int)
insert into #tmp (buyer, lenderid)
select 'Luke Skywalker', 100
union
select 'Leia Organa', 400
union
select 'Han Solo', 500
union
select 'Chewbacca', 300
union
select 'Govenor Tarkin', 200
union
select 'Darth Vader', 200
create table #assignees (contract_assignee varchar(1000), contract_assignee_address varchar(1000), lenderid int)
insert into #assignees
select 'Toshi Credit Union', '142 Sandstone Dr, Tattooine', 0
union
select 'First National Bank of Coruscant', '253 Exegol Parkway', 200
union
select 'Jawa Predatory Loans', 'Somewhere in the Desert', 300
update #tmp
set contract_assignee = a.contract_assignee
, contract_assignee_address = a.contract_assignee_address
from (select * from #assignees where lenderid = 0) a -- the default value
update t
set contract_assignee = a.contract_assignee
, contract_assignee_address = a.contract_assignee_address
from #tmp t
inner join #assignees a
on t.lenderid = a.lenderid
select * from #tmp
drop table #assignees
drop table #tmp
One method would to always JOIN to the "default" row, and then LEFT JOIN to the actual row. Then you can use ISNULL to return the "default" value when the actual row wasn't found:
UPDATE T
SET contract_assignee = ISNULL(a.contract_assignee,d.contract_assignee),
contract_assignee_address = ISNULL(a.contract_assignee_address,d.contract_assignee_address)
FROM #TMP T
JOIN #assignees d ON d.lenderid = 0
LEFT JOIN #assignees a ON t.lenderid = a.lenderid;

Removal of Cursor in SQL

Its always been discouraged to use cursor, which have been extensively used in our current stored procedures and replace them with set based queries. But this particular scenario is one, where I did not get solution to use set based query and forced to keep using the cursor. I am providing below sample code which represents the scenario:
DECLARE #temp varchar(10), #continuechar varchar(10)
DECLARE #table1 table (col1 varchar(10))
insert into #table1
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G'
DECLARE Cursor1 CURSOR for select Col1 from #table1
open Cursor1
FETCH NEXT from Cursor1 into #temp
WHILE ##FETCH_STATUS = 0
BEGIN
if #temp='A'
BEGIN
set #continuechar=#temp
END
if #temp='C'
BEGIN
set #continuechar=#temp
END
select #continuechar, #temp
FETCH NEXT from Cursor1 into #temp
END
CLOSE cursor1;
deallocate cursor1
Here in above sample code #continuechar variable is not getting set, every time cursor is getting executed. If #continuechar is getting set, then following select statement is providing result set with current value of #continuechar:
select #continuechar, #temp
if its not getting set, then its using the previously set value to provide result set.
Can we have set based queries to remove cursor from such scenario.
First I would add some id column to get stable sort. Then simply use windowed functions:
SUM() OVER() to calculate groups
FIRST_VALUE() OVER() to propagate first value across group
(present from SQL Server 2012, you could exchange it with MAX(continuechar) OVER(PARTITION BY grp) if necessary)
DECLARE #table1 table (id INT IDENTITY(1,1), col1 varchar(10))
insert into #table1
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G';
WITH cte AS (
SELECT id
,col1
,CASE WHEN col1 IN('A', 'C') THEN col1 END AS continuechar
,SUM(CASE WHEN col1 IN ('A', 'C') THEN 1 ELSE 0 END)
OVER(ORDER BY id) AS grp
FROM #table1
)
SELECT id, col1,
FIRST_VALUE(continuechar) OVER(PARTITION BY grp ORDER BY id) AS continuechar
FROM cte
ORDER BY id;
DBFiddle Demo
EDIT:
Quirky update This is for pure demo only. Do not use this method on production system:
DECLARE #table1 table (id INT IDENTITY(1,1) PRIMARY KEY, col1 varchar(10),
continue_char VARCHAR(10));
DECLARE #temp VARCHAR(10);
insert into #table1(col1)
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G';
UPDATE #table1
SET #temp = CASE WHEN col1 IN ('A','C') THEN col1 ELSE #temp END
,continue_char = #temp
OPTION(MAXDOP 1);
SELECT *
FROM #table1;
DBFiddle Demo2

Update column information

I am trying to update information in the column Mgrstat to a 3 and would like to mass enter the information. As it is I have to use "=" and enter each AppID individually but I would rather enter several at once. The query below shows my attempt using "in", which didn't work either. I get "Incorrect syntax near the keword 'in'".
Any ideas? Thanks everyone!
declare #appid as int
declare #mgrstat as int
set #appid in ('10995',
'11201',
'9523',
'9558',
'9666',
'10069',
'10547',
'10548',
'9702',
'10698',
'9754',
'10161',
'10162',
'11240',
'11241',
'9553',
'10848',
'10667',
'9383',
'10709',
'9696',
'10053',
'10702')
set #mgrstat = 3
update [Compensation].[dbo].[dev_RPT_Approval]
set Mgr_Stat = #mgrstat
FROM [Compensation].[dbo].[dev_RPT_Approval]
where #appid = App_Id
select *
from [Compensation].[dbo].[dev_RPT_Approval]
where #appid = App_Id
This is the SQL you Need:
update dev_RPT_Approval set Mgr_Stat=3
where designation
in ('10995',
'11201',
'9523',
'9558',
'9666',
'10069',
'10547',
'10548',
'9702',
'10698',
'9754',
'10161',
'10162',
'11240',
'11241',
'9553',
'10848',
'10667',
'9383',
'10709',
'9696',
'10053',
'10702')
If i'm understanding correctly, and you want all mgr_stats to be 3 where the app_id is in the list provided in your question, then you could do this a few ways:
update [Compensation].[dbo].[dev_RPT_Approval]
set Mgr_Stat = 3
where app_id in (
'10995',
'11201',
'9523',
'9558',
'9666',
'10069',
'10547',
'10548',
'9702',
'10698',
'9754',
'10161',
'10162',
'11240',
'11241',
'9553',
'10848',
'10667',
'9383',
'10709',
'9696',
'10053',
'10702'
)
or (sql server using table variable)
declare #ids table (id varchar(50))
insert into #ids (id)
select '10995'
union all select '11201'
union all select '9523'
union all select '9558'
union all select '9666'
union all select '10069'
union all select '10547'
union all select '10548'
union all select '9702'
union all select '10698'
union all select '9754'
union all select '10161'
union all select '10162'
union all select '11240'
union all select '11241'
union all select '9553'
union all select '10848'
union all select '10667'
union all select '9383'
union all select '10709'
union all select '9696'
union all select '10053'
union all select '10702'
update [Compensation].[dbo].[dev_RPT_Approval]
set Mgr_Stat = 3
from [Compensation].[dbo].[dev_RPT_Approval] t
inner join #ids i on t.app_id = i.id
A few things to note about the code you had posted:
declare #appid as int
set #appId in ...
A few things with this - #appId is declared as an integer, meaning it is a scalar value (cannot be a set) - for sets of values, you can use a table variable as I did in my second example of how to accomplish your question.
Additionally, because you variable as an int, I'm assuming your ID is of type int, the quotes are not needed.
Instead of:
where app_id in (
'10995',
....
)
you can do:
where app_id in (
10995,
....
)
can you try this?
Might work for you dude. Here you are passing multiple values using "=" instead "IN"
update [Compensation].[dbo].[dev_RPT_Approval]
set Mgr_Stat = #mgrstat
FROM [Compensation].[dbo].[dev_RPT_Approval]
where App_Id IN(#appid)

T-Sql count string sequences over multiple rows

How can I find subsets of data over multiple rows in sql?
I want to count the number of occurrences of a string (or number) before another string is found and then count the number of times this string occurs before another one is found.
All these strings can be in random order.
This is what I want to achieve:
I have one table with one column (columnx) with data like this:
A
A
B
C
A
B
B
The result I want from the query should be like this:
2 A
1 B
1 C
1 A
2 B
Is this even possible in sql or would it be easier just to write a little C# app to do this?
Since, as per your comment, you can add a column that will unambiguously define the order in which the columnx values go, you can try the following query (provided the SQL product you are using supports CTEs and ranking functions):
WITH marked AS (
SELECT
columnx,
sortcolumn,
grp = ROW_NUMBER() OVER ( ORDER BY sortcolumn)
- ROW_NUMBER() OVER (PARTITION BY columnx ORDER BY sortcolumn)
FROM data
)
SELECT
columnx,
COUNT(*)
FROM marked
GROUP BY
columnx,
grp
ORDER BY
MIN(sortcolumn)
;
You can see the method in work on SQL Fiddle.
If sortcolumn is an auto-increment integer column that is guaranteed to have no gaps, you can replace the first ROW_NUMBER() expression with just sortcolumn. But, I guess, that cannot be guaranteed in general. Besides, you might indeed want to sort on a timestamp instead of an integer.
I dont think you can do it with a single select.
You can use AdventureWorks cursor:
create table my_Strings
(
my_string varchar(50)
)
insert into my_strings values('A'),('A'),('B'),('C'),('A'),('B'),('B') -- this method will only work on SQL Server 2008
--select my_String from my_strings
declare #temp_result table(
string varchar(50),
nr int)
declare #myString varchar(50)
declare #myLastString varchar(50)
declare #nr int
set #myLastString='A' --set this with the value of your FIRST string on the table
set #nr=0
DECLARE string_cursor CURSOR
FOR
SELECT my_string as aux_column FROM my_strings
OPEN string_cursor
FETCH NEXT FROM string_cursor into #myString
WHILE ##FETCH_STATUS = 0 BEGIN
if (#myString = #myLastString) begin
set #nr=#nr+1
set #myLastString=#myString
end else begin
insert into #temp_result values (#myLastString, #nr)
set #myLastString=#myString
set #nr=1
end
FETCH NEXT FROM string_cursor into #myString
END
insert into #temp_result values (#myLastString, #nr)
CLOSE string_cursor;
DEALLOCATE string_cursor;
select * from #temp_result
Result:
A 2
B 1
C 1
A 1
B 2
Try this :
;with sample as (
select 'A' as columnx
union all
select 'A'
union all
select 'B'
union all
select 'C'
union all
select 'A'
union all
select 'B'
union all
select 'B'
), data
as (
select columnx,
Row_Number() over(order by (select 0)) id
from sample
) , CTE as (
select * ,
Row_Number() over(order by (select 0)) rno from data
) , result as (
SELECT d.*
, ( SELECT MAX(ID)
FROM CTE c
WHERE NOT EXISTS (SELECT * FROM CTE
WHERE rno = c.rno-1 and columnx = c.columnx)
AND c.ID <= d.ID) AS g
FROM data d
)
SELECT columnx,
COUNT(1) cnt
FROM result
GROUP BY columnx,
g
Result :
columnx cnt
A 2
B 1
C 1
A 1
B 2

Simplest way to do a recursive self-join?

What is the simplest way of doing a recursive self-join in SQL Server? I have a table like this:
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
5 YT NULL
6 IS 5
And I want to be able to get the records only related to a hierarchy starting with a specific person. So If I requested CJ's hierarchy by PersonID=1 I would get:
PersonID | Initials | ParentID
1 CJ NULL
2 EB 1
3 MB 1
4 SW 2
And for EB's I'd get:
PersonID | Initials | ParentID
2 EB 1
4 SW 2
I'm a bit stuck on this can can't think how to do it apart from a fixed-depth response based on a bunch of joins. This would do as it happens because we won't have many levels but I would like to do it properly.
Thanks! Chris.
WITH q AS
(
SELECT *
FROM mytable
WHERE ParentID IS NULL -- this condition defines the ultimate ancestors in your chain, change it as appropriate
UNION ALL
SELECT m.*
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
By adding the ordering condition, you can preserve the tree order:
WITH q AS
(
SELECT m.*, CAST(ROW_NUMBER() OVER (ORDER BY m.PersonId) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM mytable m
WHERE ParentID IS NULL
UNION ALL
SELECT m.*, q.bc + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.PersonID) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN
FROM mytable m
JOIN q
ON m.parentID = q.PersonID
)
SELECT *
FROM q
ORDER BY
bc
By changing the ORDER BY condition you can change the ordering of the siblings.
Using CTEs you can do it this way
DECLARE #Table TABLE(
PersonID INT,
Initials VARCHAR(20),
ParentID INT
)
INSERT INTO #Table SELECT 1,'CJ',NULL
INSERT INTO #Table SELECT 2,'EB',1
INSERT INTO #Table SELECT 3,'MB',1
INSERT INTO #Table SELECT 4,'SW',2
INSERT INTO #Table SELECT 5,'YT',NULL
INSERT INTO #Table SELECT 6,'IS',5
DECLARE #PersonID INT
SELECT #PersonID = 1
;WITH Selects AS (
SELECT *
FROM #Table
WHERE PersonID = #PersonID
UNION ALL
SELECT t.*
FROM #Table t INNER JOIN
Selects s ON t.ParentID = s.PersonID
)
SELECT *
FROm Selects
The Quassnoi query with a change for large table. Parents with more childs then 10: Formating as str(5) the row_number()
WITH q AS
(
SELECT m.*, CAST(str(ROW_NUMBER() OVER (ORDER BY m.ordernum),5) AS VARCHAR(MAX)) COLLATE Latin1_General_BIN AS bc
FROM #t m
WHERE ParentID =0
UNION ALL
SELECT m.*, q.bc + '.' + str(ROW_NUMBER() OVER (PARTITION BY m.ParentID ORDER BY m.ordernum),5) COLLATE Latin1_General_BIN
FROM #t m
JOIN q
ON m.parentID = q.DBID
)
SELECT *
FROM q
ORDER BY
bc
SQL 2005 or later, CTEs are the standard way to go as per the examples shown.
SQL 2000, you can do it using UDFs -
CREATE FUNCTION udfPersonAndChildren
(
#PersonID int
)
RETURNS #t TABLE (personid int, initials nchar(10), parentid int null)
AS
begin
insert into #t
select * from people p
where personID=#PersonID
while ##rowcount > 0
begin
insert into #t
select p.*
from people p
inner join #t o on p.parentid=o.personid
left join #t o2 on p.personid=o2.personid
where o2.personid is null
end
return
end
(which will work in 2005, it's just not the standard way of doing it. That said, if you find that the easier way to work, run with it)
If you really need to do this in SQL7, you can do roughly the above in a sproc but couldn't select from it - SQL7 doesn't support UDFs.
Check following to help the understand the concept of CTE recursion
DECLARE
#startDate DATETIME,
#endDate DATETIME
SET #startDate = '11/10/2011'
SET #endDate = '03/25/2012'
; WITH CTE AS (
SELECT
YEAR(#startDate) AS 'yr',
MONTH(#startDate) AS 'mm',
DATENAME(mm, #startDate) AS 'mon',
DATEPART(d,#startDate) AS 'dd',
#startDate 'new_date'
UNION ALL
SELECT
YEAR(new_date) AS 'yr',
MONTH(new_date) AS 'mm',
DATENAME(mm, new_date) AS 'mon',
DATEPART(d,#startDate) AS 'dd',
DATEADD(d,1,new_date) 'new_date'
FROM CTE
WHERE new_date < #endDate
)
SELECT yr AS 'Year', mon AS 'Month', count(dd) AS 'Days'
FROM CTE
GROUP BY mon, yr, mm
ORDER BY yr, mm
OPTION (MAXRECURSION 1000)
DELIMITER $$
DROP PROCEDURE IF EXISTS `myprocDURENAME`$$
CREATE DEFINER=`root`#`%` PROCEDURE `myprocDURENAME`( IN grp_id VARCHAR(300))
BEGIN
SELECT h.ID AS state_id,UPPER(CONCAT( `ACCNAME`,' [',b.`GRPNAME`,']')) AS state_name,h.ISACTIVE FROM accgroup b JOIN (SELECT get_group_chield (grp_id) a) s ON FIND_IN_SET(b.ID,s.a) LEFT OUTER JOIN acc_head h ON b.ID=h.GRPID WHERE h.ID IS NOT NULL AND H.ISACTIVE=1;
END$$
DELIMITER ;
////////////////////////
DELIMITER $$
DROP FUNCTION IF EXISTS `get_group_chield`$$
CREATE DEFINER=`root`#`%` FUNCTION `get_group_chield`(get_id VARCHAR(999)) RETURNS VARCHAR(9999) CHARSET utf8
BEGIN
DECLARE idd VARCHAR(300);
DECLARE get_val VARCHAR(300);
DECLARE get_count INT;
SET idd=get_id;
SELECT GROUP_CONCAT(id)AS t,COUNT(*) t1 INTO get_val,get_count FROM accgroup ag JOIN (SELECT idd AS n1) d ON FIND_IN_SET(ag.PRNTID,d.n1);
SELECT COUNT(*) INTO get_count FROM accgroup WHERE PRNTID IN (idd);
WHILE get_count >0 DO
SET idd=CONCAT(idd,',', get_val);
SELECT GROUP_CONCAT(CONCAT('', id ,'' ))AS t,COUNT(*) t1 INTO get_val,get_count FROM accgroup ag JOIN (SELECT get_val AS n1) d ON FIND_IN_SET(ag.PRNTID,d.n1);
END WHILE;
RETURN idd;
-- SELECT id FROM acc_head WHERE GRPID IN (idd);
END$$
DELIMITER ;