Concate string into temp table in cursor - sql

I have a temp table structure #temp2 like this
route total driverID
------------------------
10B 300
7B 400
and would like to add the driverID column with a result like 5555, 68989
to do this, I use the cursor to loop another table look like this
driverID routeNo
-------------------
5555 10B
68989 10B
72000 7B
Here is the code
declare #driverID varchar(max)
declare #routeNew varchar(20)
DECLARE brand_cursor CURSOR FOR
select distinct driver_id, route_number from [dbcwl].[dbo].[collection_deduction_summary]
where YEAR(trans_date) = #year
and MONTH(trans_date) = #month
and route_number in (select actual_route from [dbcwl].[dbo].[livedispatchingdata_pmhs_daily_summary] where status = 'OK' and YEAR(trans_date) = #year AND month(trans_date) = #month )
and vehicle_id in (select vehicle_id from [dbcwl].[dbo].[livedispatchingdata_pmhs_daily_summary] where status = 'OK' and YEAR(trans_date) = #year AND month(trans_date) = #month )
group by route_number, driver_id
OPEN brand_cursor
FETCH NEXT FROM brand_cursor
INTO #driverID, #routeNew
WHILE ##FETCH_STATUS = 0
BEGIN
--update #temp2
update #temp2 set driverID += ','+ #driverID where routeNo = #routeNew;
FETCH NEXT FROM brand_cursor
INTO #driverID, #routeNew
END
CLOSE brand_cursor;
DEALLOCATE brand_cursor;
sadly, I got the driverID column is null
and would like to have finalized temp table look like this:
route total driverID
------------------------
10B 300 5555,68989
7B 400 72000

;with cte as -- Step 1: Get all Driver Ids by routeNo
(
SELECT routeNo, driverID =
STUFF((SELECT DISTINCT ', ' + CAST(driverID AS NVARCHAR(100))
FROM #A b
WHERE b.routeNo = a.routeNo
FOR XML PATH('')), 1, 2, '')
FROM #A a
GROUP BY routeNo
)
update b -- Step 2: Update driverID accordingly.
set driverID = cte.driverID
from #B b
inner join cte on b.route = cte.routeNo
Result here

You can string_agg():
update t
set t.driverID = ot.drivers
from #temp2 t join
(select ot.routeNo, string_agg(driverID, ',') as drivers
from othertable ot
group by ot.routeNo
) ot
on t.routeNo = ot.routeNo;

Related

How do I modify this T-SQL query so that its ouput can be joined with a table in my database?

I am using SQl Server 2014. I have the following T-SQL query (with its corresponding output given below):
USE mydatabase
declare #t table (StayID int)
insert into #t select distinct StayID from DateOfBirth
while ((select count(1) from #t) > 0)
begin
declare #Id int = (select top 1 StayID from #t)
declare #age_tab table (StayID int, Age int, Year1 date)
declare #cage1 smallint = 2, #cage2 smallint = 5
declare #i_a int = (select AdultCount from DateOfBirth where StayID = #Id)
declare #i_c1 int = (select [0-3] from DateOfBirth where StayID = #Id)
declare #i_c2 int = (select [4-6] from DateOfBirth where StayID = #Id)
declare #age int = (select Age from DateOfBirth where StayID = #Id)
declare #Year1 date = (select cast(datepart(year,ArrivalDate) as varchar) from DateOfBirth where StayID = #Id)
while (#i_a>1)
begin
insert into #age_tab select #Id, (#age + 2), #Year1
set #age-=2
set #i_a-=1
end
while (#i_c1>0)
begin
insert into #age_tab select #Id, #cage1, #Year1
set #i_c1-=1
end
while (#i_c2>0)
begin
insert into #age_tab select #Id, #cage2, #Year1
set #i_c2-=1
end
insert into #age_tab select StayID, Age, cast(datepart(year,ArrivalDate) as varchar) from DateOfBirth where StayID = #Id
delete #t where StayID = #Id
end
select * from #age_tab
order by StayID, Age desc
The output of the above query is as follows:
StayID Age Year1
101 54 2016-01-01
101 52 2016-01-01
102 42 2016-01-01
102 40 2016-01-01
102 14 2016-01-01
...
I want to join the output of this query with values from another table in my database. Given the above query uses temporary tables to perform its operation, I am unable to wrap it into a CTE.
The additional information I want to bring to my output is stored in, say, table "t2".
Let's say the output from the query above is temporarily stored in a table called "t1"
So, I want to do something like this:
Select a.*
, b.Cty
from t1 a
LEFT JOIN t2 b on b.StayID = a.StayID
How can I do this?

How to find Missing number in Sequence field using SQL?

I have a table called Student and field name called StudentNumber
Student Table
StudentNumber
-------------
1
2
3
4
5
8
10
Expecting output
6
7
9
I tried like below
Declare #trans int;
set #trans = 1;
while(#trans <=50000)
BEGIN
if((select StudentNumber from [Student] where StudentNumber = #trans) != #trans)
BEGIN
print #trans;
END
END
set #trans = #trans + 1;
You could use (SQL Server 2016 and above):
SELECT Number
FROM (select cast([key] as int) +
(SELECT MIN(StudentNumber) FROM Students) as number
from OPENJSON( '[1'
+ replicate(',1',(SELECT MAX(StudentNumber) FROM Students)-
(SELECT MIN(StudentNumber) FROM Students))+']')) n
LEFT JOIN Students s
ON n.number = s.StudentNumber
WHERE s.StudentNumber IS NULL;
DBFiddle Demo
Note: You could exchange first subquery with any other tally number generator.
More info: SQL, Auxiliary table of numbers
it should be like below
Declare #trans int;
set #trans = 1;
while(#trans <=50000)
BEGIN
if NOT EXISTS (select StudentNumber from [Student] where StudentNumber = #trans)
BEGIN
print #trans;
END
END
set #trans = #trans + 1;
You can do the following
;with report as(
select 1 as missing
union all
select missing + 1
from report
where missing < #max
)
select *
from report m
where not exists ( select 1 from student s where s.id = m.missing)
option (maxrecursion 0);
Here a working demo
Result
missing
6
7
9
Hope that this will help you
I know you try to solve it iterative, just for sports
an idea how to achieve the same using recursive CTE
with missingstudents (StudentNumber)
as (
select StudentNumber-1 from Students s
where not exists (
select StudentNumber from Students s2
where s.StudentNumber-1 = s2.StudentNumber)
UNION ALL
select StudentNumber-1 from missingstudents s
where not exists (
select StudentNumber from Students s2
where s.StudentNumber-1 = s2.StudentNumber)
)
select * from missingstudents
You can try this:
select m.number from
(select min(StudentNumber) a,max(StudentNumber) b from Students) c ,master..spt_values M
where c.a <= m.number
and c.b > = m.number
and type ='P'
and m.number not in (select StudentNumber from Students)
Try like this;
declare #id int
declare #maxStudentNumber int
set #id = 1
select #maxStudentNumber = max(StudentNumber) from Student
create table #MissingIds
(
id int
)
while #id < #maxStudentNumber
begin
insert into #MissingIds values(#id)
set #id = #id + 1
end
select m.id
from #MissingIds m
left join Student s
on m.id = s.StudentNumber
where s.StudentNumber is null
drop table #MissingIds

Convert rows to columns without using pivot

How can i convert this rows :
id id_name flag tag_name tag_type tag_value
1 1 163 XO c 10
1 1 163 X1 c 0
1 1 163 AM c 5
to this one row :
1 1 163 XO:c:10 X1:c:0 AM:c:5
Without using pivot ??
You're looking to do the equivalent of a group_concat, rather than a pivot
;with src as (select id, id_name, flag, tag_name+':'+tag_type+':'+CONVERT(varchar(5), tag_value) as tag from yourtable t1 )
SELECT distinct
src.id, src.id_name, src.flag,
tags = STUFF((
SELECT ' ' + s.tag
FROM src s
WHERE s.id=src.id
FOR XML PATH(''), TYPE).value('.', 'varchar(max)'), 1, 1, '')
FROM src
Here is one possible way to pivot your data like you've asked. Generally it would be better to perform this sort of string building/manipulation within your application rather then on the database directly. In this example Table2 can be swapped for a temporary table.
-- Create and Seed Table2
SELECT [id], [id_name], [flag], CAST(NULL as varchar(255)) AS [data]
INTO [Table2] FROM [Table1]
GROUP BY [id], [id_name], [flag];
-- Declare variables to hold row
DECLARE #id int, #id_name int, #flag int,
#tag_name varchar(2), #tag_type varchar(1), #tag_value int;
-- Declare the Cursor
DECLARE PivotCursor CURSOR FOR
SELECT [id], [id_name], [flag], [tag_name], [tag_type], [tag_value]
FROM [Table1] ORDER BY [id], [id_name], [flag], [tag_name]
;
-- Use the cursor to update Table2
OPEN PivotCursor;
FETCH NEXT FROM PivotCursor INTO #id, #id_name, #flag, #tag_name, #tag_type, #tag_value;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE Table2 SET
[Data] = ISNULL([Data],'')+(CASE WHEN [Data] IS NULL THEN '' ELSE ' ' END)+#TagName+':'+#TagType+':'+CAST(#TagValue as varchar)
WHERE [id] = #id AND [id_name] = #id_name AND [flag] = #flag;
-- Get Next
FETCH NEXT FROM PivotCursor INTO #id, #id_name, #flag, #tag_name, #tag_type, #tag_value;
END
CLOSE PivotCursor;
DEALLOCATE PivotCursor;
The resulting table looks like this:
id id_name flag data
1 1 163 AM:c:5 X1:c:0 XO:c:10

Is it possible to group unlike items and count them together?

Given the following table:
Chain Name
123 Company 1
124 Other Company 1
123 Whatever Company
125 This One
126 That One
125 Another One
127 Last One
I get the following results when I do a Count on the Chain column:
123 2
124 1
125 2
126 1
127 1
Is it possible to group Chain 123 and 124 so they're counted together? Also group 125 and 126? The modified results would look like this:
123/124 3
125/126 3
127 1
My SQL looks like this:
SELECT Table1.Chain, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY Table1.Chain
ORDER BY Table1.Chain;
Thank you!
Depending upon your needs, this might be a bit of a hack, but I would probably add a table to store the Chain and ChainGroup that you are seeking. Something like this:
Chain ChainGroup
123 123/124
124 123/124
125 125/126
126 125/126
127 127/128
Then, in the query, I would join to this table and instead of grouping by Chain I would group by ChainGroup.
I would prefer this over something like a nested IIF statement as those get pretty difficult to debug, and odds are you'll have additional groupings in the future which would be trivial to add to the table and have the new grouping automatically appear in the query.
yes, you can:
SELECT min(Table1.Chain) & '/' & max(Table1.Chain) as chain, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY int((Table1.Chain-1)/2)
ORDER BY min(Table1.Chain);
You can use a nested Iif statement. Hopefully I've got all my parentheses right below! :-)
SELECT Iif(Table1.Chain="123", "123/124",
Iif(Table1.Chain="124", "123/124",
Iif(Table1.Chain="125", "125/126",
Iif(Table1.Chain="126", "125/126", Table1.Chain)))) as [Chain]
, Count(*) as [Count]
FROM Table1 LEFT JOIN Table2 on Table1.Chain = Table2.Chain
WHERE (((Table1.Chain) IN (Table2.Chain)))
GROUP BY Iif(Table1.Chain="123", "123/124",
Iif(Table1.Chain="124", "123/124",
Iif(Table1.Chain="125", "125/126",
Iif(Table1.Chain="126", "125/126", Table1.Chain))))
ORDER BY Table1.Chain;
You could also move the case statement into a subquery in your from clause or a common table expression if you don't want to write it twice in your query.
consider something like:
SELECT
chain_group, COUNT(*) FROM (
SELECT
Table1.Chain,
switch(Table1.Chain IN("123","124"), "123/124",
Table1.Chain IN("125","126"),"125/126",
Table1.Chain) AS chain_group
FROM
Table1 INNER JOIN
Table2 ON
Table1.Chain = Table2.Chain) t
GROUP BY chain_group
ORDER BY chain_group
You can see the below example
----- Make main Table
CREATE TABLE #test
( id int , Name varchar(100))
INSERT #test(id,Name)
values (123,'Company 1'),
(124,'Other Company 1'),
(123, 'Whatever Company'),
(125, 'This One'),
(126 , 'That One'),
(125, 'Another One'),
(127, 'Last One')
CREATE TABLE #temp
(rowID INT IDENTITY(1,1) , ID INT ,cnt INT )
CREATE TABLE #tempResult
(ID VARCHAR(20) ,cnt INT )
INSERT INTO #temp(ID,cnt)
SELECT ID ,COUNT(1) cnt FROM #test GROUP BY ID
DECLARE #rowCnt INT , #TotalCnt INT , #even INT , #odd INT ,
#idNum VARCHAR(20) , #valueCnt INT , #inStart INT = 1
SET #rowCnt = 1
SET #even = 1
SET #odd = 2
SELECT #TotalCnt = COUNT(1) FROM #temp
WHILE #rowCnt <= #TotalCnt
BEGIN
SET #inStart = 1
SET #odd = #rowCnt
SET #even = #rowCnt + 1
SET #idNum = ''
SET #valueCnt = 0
WHILE #inStart <= 2
BEGIN
IF #inStart = 1
Begin
SELECT #idNum = Convert(VARCHAR(5),ID) , #valueCnt = cnt
FROM #temp WHERE rowID = #odd
End
ELSE
BEGIN
SELECT #idNum = #idNum + '/' + Convert(VARCHAR(5),ID) , #valueCnt = #valueCnt + cnt
FROM #temp WHERE rowID = #even
END
SET #inStart = #inStart + 1
END
INSERT INTO #tempResult (ID, Cnt)
VALUES (#idNum,#valueCnt)
SET #rowCnt = #rowCnt + 2
END
SELECT *
FROM #tempResult

SQL query to find Missing sequence numbers

I have a column named sequence. The data in this column looks like 1, 2, 3, 4, 5, 7, 9, 10, 15.
I need to find the missing sequence numbers from the table. What SQL query will find the missing sequence numbers from my table? I am expecting results like
Missing numbers
---------------
6
8
11
12
13
14
I am using only one table. I tried the query below, but am not getting the results I want.
select de.sequence + 1 as sequence from dataentry as de
left outer join dataentry as de1 on de.sequence + 1 = de1.sequence
where de1.sequence is null order by sequence asc;
How about something like:
select (select isnull(max(val)+1,1) from mydata where val < md.val) as [from],
md.val - 1 as [to]
from mydata md
where md.val != 1 and not exists (
select 1 from mydata md2 where md2.val = md.val - 1)
giving summarised results:
from to
----------- -----------
6 6
8 8
11 14
I know this is a very old post but I wanted to add this solution that I found HERE so that I can find it easier:
WITH Missing (missnum, maxid)
AS
(
SELECT 1 AS missnum, (select max(id) from #TT)
UNION ALL
SELECT missnum + 1, maxid FROM Missing
WHERE missnum < maxid
)
SELECT missnum
FROM Missing
LEFT OUTER JOIN #TT tt on tt.id = Missing.missnum
WHERE tt.id is NULL
OPTION (MAXRECURSION 0);
Try with this:
declare #min int
declare #max int
select #min = min(seq_field), #max = max(seq_field) from [Table]
create table #tmp (Field_No int)
while #min <= #max
begin
if not exists (select * from [Table] where seq_field = #min)
insert into #tmp (Field_No) values (#min)
set #min = #min + 1
end
select * from #tmp
drop table #tmp
The best solutions are those that use a temporary table with the sequence. Assuming you build such a table, LEFT JOIN with NULL check should do the job:
SELECT #sequence.value
FROM #sequence
LEFT JOIN MyTable ON #sequence.value = MyTable.value
WHERE MyTable.value IS NULL
But if you have to repeat this operation often (and more then for 1 sequence in the database), I would create a "static-data" table and have a script to populate it to the MAX(value) of all the tables you need.
SELECT CASE WHEN MAX(column_name) = COUNT(*)
THEN CAST(NULL AS INTEGER)
-- THEN MAX(column_name) + 1 as other option
WHEN MIN(column_name) > 1
THEN 1
WHEN MAX(column_name) <> COUNT(*)
THEN (SELECT MIN(column_name)+1
FROM table_name
WHERE (column_name+ 1)
NOT IN (SELECT column_name FROM table_name))
ELSE NULL END
FROM table_name;
Here is a script to create a stored procedure that returns missing sequential numbers for a given date range.
CREATE PROCEDURE dbo.ddc_RolledBackOrders
-- Add the parameters for the stored procedure here
#StartDate DATETIME ,
#EndDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Min BIGINT
DECLARE #Max BIGINT
DECLARE #i BIGINT
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable
END
CREATE TABLE #TempTable
(
TempOrderNumber BIGINT
)
SELECT #Min = ( SELECT MIN(ordernumber)
FROM dbo.Orders WITH ( NOLOCK )
WHERE OrderDate BETWEEN #StartDate AND #EndDate)
SELECT #Max = ( SELECT MAX(ordernumber)
FROM dbo.Orders WITH ( NOLOCK )
WHERE OrderDate BETWEEN #StartDate AND #EndDate)
SELECT #i = #Min
WHILE #i <= #Max
BEGIN
INSERT INTO #TempTable
SELECT #i
SELECT #i = #i + 1
END
SELECT TempOrderNumber
FROM #TempTable
LEFT JOIN dbo.orders o WITH ( NOLOCK ) ON tempordernumber = o.OrderNumber
WHERE o.OrderNumber IS NULL
END
GO
Aren't all given solutions way too complex?
wouldn't this be much simpler:
SELECT *
FROM (SELECT row_number() over(order by number) as N from master..spt_values) t
where N not in (select 1 as sequence union
select 2 union
select 3 union
select 4 union
select 5 union
select 7 union
select 10 union
select 15
)
This is my interpretation of this issue, placing the contents in a Table variable that I can easily access in the remainder of my script.
DECLARE #IDS TABLE (row int, ID int)
INSERT INTO #IDS
select ROW_NUMBER() OVER (ORDER BY x.[Referred_ID]), x.[Referred_ID] FROM
(SELECT b.[Referred_ID] + 1 [Referred_ID]
FROM [catalog].[dbo].[Referrals] b) as x
LEFT JOIN [catalog].[dbo].[Referrals] a ON x.[Referred_ID] = a.[Referred_ID]
WHERE a.[Referred_ID] IS NULL
select * from #IDS
Just for fun, I decided to post my solution.
I had an identity column in my table and I wanted to find missing invoice numbers.
I reviewed all the examples I could find but they were not elegant enough.
CREATE VIEW EENSkippedInvoicveNo
AS
SELECT CASE WHEN MSCNT = 1 THEN CAST(MSFIRST AS VARCHAR (8)) ELSE
CAST(MSFIRST AS VARCHAR (8)) + ' - ' + CAST(MSlAST AS VARCHAR (8)) END AS MISSING,
MSCNT, INV_DT FROM (
select invNo+1 as Msfirst, inv_no -1 as Mslast, inv_no - invno -1 as msCnt, dbo.fmtdt(Inv_dt) AS INV_dT
from (select inv_no as invNo, a4glidentity + 1 as a4glid
from oehdrhst_sql where inv_dt > 20140401) as s
inner Join oehdrhst_sql as h
on a4glid = a4glidentity
where inv_no - invno <> 1
) AS SS
DECLARE #MaxID INT = (SELECT MAX(timerecordid) FROM dbo.TimeRecord)
SELECT SeqID AS MissingSeqID
FROM (SELECT ROW_NUMBER() OVER (ORDER BY column_id) SeqID from sys.columns) LkUp
LEFT JOIN dbo.TimeRecord t ON t.timeRecordId = LkUp.SeqID
WHERE t.timeRecordId is null and SeqID < #MaxID
I found this answer here:
http://sql-developers.blogspot.com/2012/10/how-to-find-missing-identitysequence.html
I was looking for a solution and found many answers. This is the one I used and it worked very well. I hope this helps anyone looking for a similar answer.
-- This will return better Results
-- ----------------------------------
;With CTERange
As (
select (select isnull(max(ArchiveID)+1,1) from tblArchives where ArchiveID < md.ArchiveID) as [from],
md.ArchiveID - 1 as [to]
from tblArchives md
where md.ArchiveID != 1 and not exists (
select 1 from tblArchives md2 where md2.ArchiveID = md.ArchiveID - 1)
) SELECT [from], [to], ([to]-[from])+1 [total missing]
From CTERange
ORDER BY ([to]-[from])+1 DESC;
from to total missing
------- ------- --------------
6 6 1
8 8 1
11 14 4
DECLARE #TempSujith TABLE
(MissingId int)
Declare #Id Int
DECLARE #mycur CURSOR
SET #mycur = CURSOR FOR Select Id From tbl_Table
OPEN #mycur
FETCH NEXT FROM #mycur INTO #Id
Declare #index int
Set #index = 1
WHILE ##FETCH_STATUS = 0
BEGIN
if (#index < #Id)
begin
while #index < #Id
begin
insert into #TempSujith values (#index)
set #index = #index + 1
end
end
set #index = #index + 1
FETCH NEXT FROM #mycur INTO #Id
END
Select Id from tbl_Table
select MissingId from #TempSujith
Create a useful Tally table:
-- can go up to 4 million or 2^22
select top 100000 identity(int, 1, 1) Id
into Tally
from master..spt_values
cross join master..spt_values
Index it, or make that single column as PK.
Then use EXCEPT to get your missing number.
select Id from Tally where Id <= (select max(Id) from TestTable)
except
select Id from TestTable
You could also solve using something like a CTE to generate the full sequence:
create table #tmp(sequence int)
insert into #tmp(sequence) values (1)
insert into #tmp(sequence) values (2)
insert into #tmp(sequence) values (3)
insert into #tmp(sequence) values (5)
insert into #tmp(sequence) values (6)
insert into #tmp(sequence) values (8)
insert into #tmp(sequence) values (10)
insert into #tmp(sequence) values (11)
insert into #tmp(sequence) values (14)
DECLARE #max INT
SELECT #max = max(sequence) from #tmp;
with full_sequence
(
Sequence
)
as
(
SELECT 1 Sequence
UNION ALL
SELECT Sequence + 1
FROM full_sequence
WHERE Sequence < #max
)
SELECT
full_sequence.sequence
FROM
full_sequence
LEFT JOIN
#tmp
ON
full_sequence.sequence = #tmp.sequence
WHERE
#tmp.sequence IS NULL
Hmmmm - the formatting is not working on here for some reason? Can anyone see the problem?
i had made a proc so you can send the table name and the key and the result is a list of missing numbers from the given table
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create PROCEDURE [dbo].[action_FindMissing_Autoincremnt]
(
#tblname as nvarchar(50),
#tblKey as nvarchar(50)
)
AS
BEGIN
SET NOCOUNT ON;
declare #qry nvarchar(4000)
set #qry = 'declare #min int '
set #qry = #qry + 'declare #max int '
set #qry = #qry +'select #min = min(' + #tblKey + ')'
set #qry = #qry + ', #max = max('+ #tblKey +') '
set #qry = #qry + ' from '+ #tblname
set #qry = #qry + ' create table #tmp (Field_No int)
while #min <= #max
begin
if not exists (select * from '+ #tblname +' where '+ #tblKey +' = #min)
insert into #tmp (Field_No) values (#min)
set #min = #min + 1
end
select * from #tmp order by Field_No
drop table #tmp '
exec sp_executesql #qry
END
GO
SELECT TOP 1 (Id + 1)
FROM CustomerNumberGenerator
WHERE (Id + 1) NOT IN ( SELECT Id FROM CustomerNumberGenerator )
Working on a customer number generator for my company. Not the most efficient but definitely most readable
The table has one Id column.
The table allows for Ids to be inserted at manually by a user off sequence.
The solution solves the case where the user decided to pick a high number