Insert into table using a select statement and a while loop - sql

I need to insert values into a table from another table. I also want to use a while loop to update a row in my table at the same time. Below you can see my query.
declare #id int
select #id = 1
while #id >=1 and #id <= 3
begin
INSERT INTO [dbo].[TEST]
([ID_PRODUCT],[PRODUCTID],[PRODUCTDESC],[COUNT]
select distinct
ID_PRODUCT,PRODUCTID,PRODUCTDESC,#id
from SAMPLES
select #id = #id + 1
end
This works but not as i was expecting. Instead of giving me three rows affected, it gives me three rows affected, three times. So i end up with nine new rows instead of the desired three i want.
ID_PRODUCT PRODUCTID PRODUCTDESC COUNT
35746 136559 Desc1 1
35747 276732 Desc2 1
35748 259910 Desc3 1
35746 136559 Desc1 2
35747 276732 Desc2 2
35748 259910 Desc3 2
35746 136559 Desc1 3
35747 276732 Desc2 3
35748 259910 Desc3 3
What i want to acheive is this :
ID_PRODUCT PRODUCTID PRODUCTDESC COUNT
35746 136559 Desc1 1
35747 276732 Desc2 2
35748 259910 Desc3 3
Can anyone see what im doing wrong?

The SELECT part of Insert statement always returns same records
#id does not change the selected rows, only inserts same data set with different #id values
select distinct
ID_PRODUCT,PRODUCTID,PRODUCTDESC,#id
from SAMPLES

You are inserting three times same list of rows with different #id.
I guess you actually mean this:
;with DistinctSampleValues as
(
select distinct
ID_PRODUCT,PRODUCTID,PRODUCTDESC
from SAMPLES
)
insert into [dbo].[TEST] ([ID_PRODUCT],[PRODUCTID],[PRODUCTDESC],[COUNT])
select
ID_PRODUCT,PRODUCTID,PRODUCTDESC,
ROW_NUMBER() OVER(ORDER BY ID_PRODUCT) RN
from DistinctSampleValues
one time insert all distinct values with additional "row number".

You are close. Add top 1 and where clause like ID_PRODUCT not in Test table
declare #id int
select #id = 1
while #id >=1 and #id <= 3
begin
INSERT INTO [dbo].[TEST]
([ID_PRODUCT],[PRODUCTID],[PRODUCTDESC],[COUNT]
SELECT DISTINCT TOP 1
ID_PRODUCT,
PRODUCTID,
PRODUCTDESC,
#id
from
SAMPLES S
WHERE
S.ID_PRODUCT NOT IN
(
SELECT T.ID_PRODUCT FROM [TEST] T
)
select #id = #id + 1
end

Eralper and Ivan Starostin both answered correctly and it is right solution for you.
To run your code correctly, you need to add WHERE clause.
declare #id int
select #id = 1
while #id >=1 and #id <= 3
begin
INSERT INTO [dbo].[TEST]
([ID_PRODUCT],[PRODUCTID],[PRODUCTDESC],[COUNT]
select distinct
ID_PRODUCT,PRODUCTID,PRODUCTDESC,#id
from
SAMPLES s
WHERE Count = #id
AND NOT EXISTS(SELECT 1 FROM Test t WHERE t.ID_PRODUCT = s.ID_PRODUCT
AND t.PRODUCTID = s.PRODUCTID)
select #id = #id + 1
end

Related

SQL Server: how to update a column with a value that is in that column when another number in another column is >1

I have a table with the following data:
Part Comp level item_nbr
-------------------------------
abc ab 1 1
null cd 2 2
null ef 3 3
cde gh 1 4
null ij 2 5
null kl 3 6
null mn 4 7
I would like to update the nulls to the value in each level 1, so every level that is >1 is updated with the level one value.
Part Comp level
---------------------
abc ab 1
abc cd 2
abc ef 3
cde gh 1
cde ij 2
cde kl 3
cde mn 4
I am at a loss as to how to achieve this on a very large dataset. Any help would be greatly appreciated!
To explain another way,
part level
abc 1
2
3
Then the next row is populated with another part
efg 1
2
2
etc.
Further clarification:
I need the string"abc" to be filled down with the string "abc" while the column fields below are null. The next row has a string of efg and the following column fields below are null, again, those fields should be filled down with the value "efg" and so on.
The level field = 1 will always have a part number, but all the other levels report up to the level 1 part, so should be populated identically. And repeat.
Hope this makes sense.
Use an updatable CTE with window functions:
with toupdate as (
select t.*,
max(part) over (partition by itm_nbr_not_null) as new_part
from (select t.*,
max(case when part is not null then item_nbr end) over (order by item_nbr) as itm_nbr_not_null
from t
) t
)
update toupdate
set part = new_part
where part is null;
You can run the CTE to see what is happening.
well, from your question what I understand is, you need to update the null column's value until you get a not null value. and you want to continue it up to the last row of the table.
for that scenario, I created a stored procedure, where I read the value of every n-th cell if it is null I changing it with the prev. cell's value, when the cell was not null.
Approach:
create a temporary table/ table variable.
add an extra column, which is basically identity, which will help to rank the column.
iterate a loop until the maximum row is reached.
in each iteration, read the cell value for the i-th row
4.1 if it is not null put it in a temporary variable.
4.2 else, replace/update the i-th cell's value with the temporary variable
continue it, until you reached up to the last row of the table/table variable.
look at my following snippets:
create proc DemoPost
as
begin
declare #table table(serial_no int identity(1,1), name varchar(30), text varchar(30), level int)
insert #table
select Name, Text, Level from Demo
declare #max as int = (select max(serial_no) from #table)
--select #max
declare #i as int =0
declare #temp as varchar(30)
declare #text as varchar(30)
while #i < #max
begin
set #i = #i +1
set #temp = (select name from #table where serial_no = #i)
-- if #temp is not null, fetch its value, otherwise, update/replace it with
-- previously gotten not-null cell's value.
if #temp is not null
begin
set #text = (select name from #table where serial_no = #i)
end
else
begin
update #table
set name = #text where serial_no = #i
end
end
select name, text, level from #table
end
You can update it using temporary table according to the given scenario i thought item_nbr is unique in row Hope this will help
SELECT *
INTO #TEMP
FROM URTablehere
DECLARE #PRev VARCHAR(MAX)
WHILE ( SELECT COUNT(*)
FROM URTablehere
) > 0
BEGIN
DECLARE #ID INT
DECLARE #Part VARCHAR(MAX)
DECLARE #Num INT
SELECT TOP ( 1 )
#ID = level ,
#Part = Part ,
#Num = item_nbr
FROM #TEMP
IF ( #ID = 1 )
BEGIN
SELECT #PRev = #Part
END
IF ( #ID > 1
AND #Part IS NULL
)
BEGIN
UPDATE URTablehere
SET Part = #PRev
WHERE item_nbr = #Num
END
DELETE
FROM #TEMP WHERE item_nbr=#Num
END

How to create loop based on value of row?

I have problem when I use my query bellow to have a looping inside the cursor.
data in table1 will be like this:
id | data
----|---------
A | 4
B | 2
C | 5
the result in table2 should be like this:
id | data
----|---------
A | 1
A | 1
A | 1
A | 1
B | 1
B | 1
C | 1
C | 1
C | 1
C | 1
C | 1
I have SQL query with cursor like this:
DECLARE #table2 table ( id VARCHAR(500), data INTEGER)
DECLARE Cur CURSOR FOR
SELECT id, data FROM table1
OPEN Cur
WHILE ( ##FETCH_STATUS = 0 )
BEGIN
DECLARE #LoopNum INTEGER
DECLARE #tempID VARCHAR(255)
DECLARE #tempDATA INTEGER
FETCH NEXT FROM Cur INTO #tempID, #tempDATA
set #LoopNum = 0
WHILE #LoopNum < #tempDATA
BEGIN
INSERT INTO table2 (id, data)
VALUES( #tempID, 1)
SET #LoopNum = #LoopNum + 1
END
END
CLOSE Cur
DEALLOCATE Cur
SELECT * FROM table2
but the query didn't work. is there something wrong with my query?
Thank you.
Use this query to the expected result.
CREATE TABLE #test
(id CHAR(1),data INT)
INSERT #test VALUES ('A',4)
INSERT #test VALUES('B',2)
INSERT #test VALUES('C',5);
SELECT s.id, 1 AS data
FROM #test s
INNER JOIN
master.dbo.spt_values t ON t.type='P'
AND t.number BETWEEN 1 AND s.data
Note: Refer this Why (and how) to split column using master..spt_values?
You actually don't need a loop
IF OBJECT_ID('TEMPDB..#TEMP') IS NOT NULL
DROP TABLE #TEMP
SELECT 'A' AS ID, 4 AS DATA
INTO #TEMP UNION
SELECT 'B', 2 UNION
SELECT 'C', 5
;WITH CTE AS
(
SELECT 1 AS NUMBER
UNION ALL
SELECT NUMBER + 1
FROM CTE
WHERE NUMBER < 100
)
SELECT T.ID, 1
FROM CTE C
INNER JOIN #TEMP T
ON C.NUMBER <= T.DATA
ORDER BY T.ID
Carefull that if you want ot generate a large set of numbers in the CTE it may become slower.
Use a Recursive CTE which will help you to loop through the records.
CREATE TABLE #test
(id CHAR(1),data INT)
INSERT #test
VALUES ('A',4),('B',2),('C',5);
WITH cte
AS (SELECT 1 AS da,id,data
FROM #test a
UNION ALL
SELECT da + 1,id,data
FROM cte a
WHERE da < (SELECT data
FROM #test b
WHERE a.id = b.id))
SELECT id,
1 AS data
FROM cte
ORDER BY id
i used two loops
1. for each row
2. for number for duplicate insert
SET NOCOUNT on;
DECLARE #t table(row int IDENTITY(1,1),id varchar(10),data int)
INSERT INTO #t
SELECT * from xyz
DECLARE #x table(id varchar(10),data int) --table to hold the new data
DECLARE #i int=(SELECT count (*) from xyz) --number of rows main table
DECLARE #y int --number of duplicate
DECLARE #p int=1 --number of rows
WHILE #i!=0 --loop until last row of main table
BEGIN
SET #y=(SELECT data FROM #t WHERE row=#p) --set #y for number of 'row duplicate'
WHILE #y!=0
BEGIN
INSERT INTO #x
SELECT id,1
FROM #t
WHERE row=#p
SET #y=#y-1
END
SET #p=#p+1
SET #i=#i-1
END
SELECT * FROM #x

How to find Missing Numbers in a table using sqlserver?

I want to find Missing Numbers in a table..Table Like this.
Sno Branch
1 ABC
2 ABC
3 ABC
5 ABC // 4th sno is missing
6 ABC
8 ABC // 7th sno is missing
10 ABC // 9th sno is missing
I found the missing SNo using this Query
ALTER proc [dbo].[K_RT_DCNoMissing]--1,50
as
begin
declare #id int
set #id = 0
declare #maxid int
--set #id = #fromvalue
select #maxid = (select count(*) dcno from K_RT_Dailyentryretail nolock)
create table #IDSeq
(
id int
)
while 0<#maxid--whatever you max is
begin
insert into #IDSeq values(#id)
set #id = #id + 1
set #maxid = #maxid - 1
-- print #maxid
end
select
s.id
from
#idseq s
left join K_RT_Dailyentryretail t on
s.id = t.dcno
where t.dcno is null order by s.id asc
drop table #IDSeq
end
I am getting out put like this..
MissingNo's
4
7
9
Now I want to Display Sno with Branch Name like.
MissingNo's Branch
4 ABC
7 ABC
9 ABC
How can i get the branch name...
Am getting output as
4 abc
4 cde
4 fgh
7 abc
7 cde
7 fgh
but what actually am expecting is
4 abc
7 cde
. ..
. ..
etc.
You can use a CTE to build a table of all the branches and the full range of numbers for each. Then left join that to the main table to find what is missing. This will allow you to get consecutive missing numbers, e.g. 3, 4 and 5 missing. You can adjust #minid and #maxid to whatever you want your range to be. If #maxid can be greater than 32767, then you will need to do something with batches of ranges.
declare #minid int, #maxid int
set #minid = 1
set #maxid = (select count(*) dcno from K_RT_Dailyentryretail with (nolock))
; with Branches as (
select distinct Branch from K_RT_Dailyentryretail
)
, CTE as
(
select #minid as Sno, Branch from Branches
union all
select Sno + 1, Branch from CTE where Sno < #maxid
)
select CTE.Sno, CTE.Branch from CTE
left outer join K_RT_Dailyentryretail k on k.Branch = CTE.Branch and CTE.Sno = k.Sno
where k.Sno is null
option (MAXRECURSION 32767);
SQLFiddle here: http://sqlfiddle.com/#!3/13653/13
I am considering that GAP between you number will be always of only 1 digit.
In this case following will work for you,
;With CTE as
(
select Sno,Branch,ROW_NUMBER() over (order by Sno) R
from C
)
select a.Sno+ 1,a.Branch from CTE as a
left join CTE as b on a.R + 1= b.R
where a.Sno + 1 <> b.Sno
One more thing is that, for missing row you want branch, I have thought that for missing row you want to have branch of previous row.
Assuming that each branch has it's own set of sno numbers, this works:
select sno-1 as sno, branch
from t1
where sno-1 NOT in (select sno from t1 as t2 where t1.branch = t2.branch)
and sno > 1
;
Which you can check here: http://sqlfiddle.com/#!3/daa81d/3
If sno is a unique key, let me know and I will revise the answer.
EDIT: Like AK47's answer, I'm assuming that the gap is only one row.

Sorting results of SQL query just like IN parameter list

I'm doing a query which looks something like
SELECT id,name FROM table WHERE id IN (2,1,4,3)
I'd like to get
id name
2 B
1 A
4 D
3 C
but I'm getting
1 A
2 B
3 C
4 D
Is there any way to sort the query results in the same way as the list I'm including after IN?
Believe me, I have a practical reason that I would need it for ;)
SELECT id,name FROM table WHERE id IN (2,1,4,3)
ORDER BY CASE id
WHEN 2 THEN 1
WHEN 1 THEN 2
WHEN 4 THEN 3
WHEN 3 THEN 4
ELSE 5
END
This might solve your problem.
Solution 2, insert your list into a temp table and get them a running sequence
id, seq(+1 every new row added)
-----------------
2 1
1 2
4 3
3 4
then join 2 table together and order by this seq.
Okay, I did it myself. It's a bit mad but it works ;)
DECLARE #IDs varchar(max)
DECLARE #nr int
DECLARE #znak varchar(1)
DECLARE #index int
DECLARE #ID varchar(max)
SET #IDs='7002,7001,7004,7003'
SET #nr=1
SET #index=1
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
CREATE TABLE #temp (nr int, id int)
--fill temp table with Ids
WHILE #index<=LEN(#Ids)
BEGIN
set #znak=''
set #ID=''
WHILE #znak<>',' AND #index<=LEN(#Ids)
BEGIN
SET #znak= SUBSTRING(#IDs,#index,1)
IF #znak<>',' SET #ID=#ID+#znak
SET #index=#index+1
END
INSERT INTO #temp(nr,id) VALUES (#nr,CAST(#ID as int))
SET #nr=#nr+1
END
-- select proper data in wanted order
SELECT MyTable.* FROM MyTable
INNER JOIN #temp ON MyTable.id=#temp.id
ORDER BY #temp.nr

FK on same table

I have table with ID who is PK and I have in same table column ParentID who is in some cases ID's.(I say some cases because for example ParentID can be 0 but this ID not have in ID's column).
I try to create Query:
ID ParentID Value
1 0 Test
2 0 Test01
3 2 Test02
4 3 Test03
And when I send ID=4 I need this result:
ID ParentID Value
2 0 Test01
3 2 Test02
4 3 Test03
Any help...
This looks like a tree traversal problem to me, which doesn't lend itself particularly well to set-based operations. The following works, but it's not too elegant:
-- turn this into stored proc?
declare #inputId int
set #inputId = 4
declare #Ids table (ID int)
insert into #Ids values (#inputId)
declare #reccount int
set #reccount = 1
declare #lastreccount int
set #lastreccount = 0
while #reccount <> #lastreccount
begin
set #lastreccount = #reccount
insert into #Ids
select ParentID from recursiveTest
where ID in (select ID from #Ids)
and ParentID not in (select ID from #Ids)
set #reccount = (select COUNT(*) from #Ids)
end
select * from recursiveTest where ID in (select ID from #Ids);
Don't use 0 (zero) but null to signal "no parent present".
try this:
Declare #Id Integer Set #Id = 4
With Child(Id, ParentId, Value, Level) As
( Select Id, ParentId, Value, 0 as Level
From table
Where id = #Id
Union All
Select t.Id, t.ParentId, t.Value, level + 1
From Child c Join table t
On t.Id = c.ParentId
)
Select id. ParentId, Value, Level
From Child
Order By Id