loop through rows and delete those with a specific value - sql

I have a question. I have for example this table in database:
row column visible
-----------------------
1 1 no
1 2 no
1 3 no
1 4 no
2 1 yes
2 2 yes
2 3 yes
2 4 yes
I want to loop through this table and to verify if all the rows have visibility "no". If all the row have the visibility no, I want that my new table to be :
row column visible
-----------------------
1 1 yes
1 2 yes
1 3 yes
1 4 yes
I am thinking at a cursor in a stored procedure like this:
create procedure someProcedure
as
declare #visible varchar(5)
declare #column int
declare #position int
declare scan cursor for
select column, position, visible
from table
where row between (select min(row) from table)
and (select max(row) from table)
order by row, column
but i don't know how to do this, I'm very new to sql,thank you

Cursors are slow and inefficient, and are very rarely needed. You don't need a cursor for this, you can use an updatable CTE to update the yes rows.
CREATE OR ALTER PROCEDURE someProcedure
AS
WITH cte AS (
SELECT *,
AnyVisible = COUNT(CASE WHEN Visible = 'yes' THEN 1 END) OVER (PARTITION BY row)
FROM [table] t
)
DELETE FROM cte
WHERE AnyVisible = 0;
WITH cte AS (
SELECT *,
rn = DENSE_RANK() OVER (ORDER BY row)
FROM [table] t
)
UPDATE cte
SET row = rn;
GO

I am not a 100% sure what you are trying to achieve but here is a small template for the cursor.
create procedure someProcedure as
declare #column int
declare #position int
declare #visible varchar(5)
declare scan cursor for
select column, position, visible
from table
where row between (select min(row) from table)
and (select max(row) from table)
order by row, column
--Open the cursor
open scan
-- fill variables with first position of cursor
fetch next from scan into #column, #position, #visible
-- start looping unit end
while(##FETCH_STATUS = 0)
begin
/*
Do things here
*/
-- move to next position in cursor
fetch next from scan into #column, #position, #visible
end
close scan
deallocate scan

Related

Convert Excel formula ' =COUNTIF($B$2:B2,[#[reg_no]]) ' to SQL

My excel sheet having a column Count is responsible for counting how many times one registration number is repeated as you can see in the given picture.
Whenever I am going to add any new record in my excel table this column go up and count how many records are there as like my reg_no
Let us take Example:
If we add new record at 17th id with
Reg_no = 3591
Name = 'dani'
grade = 'A'
Count ?
Now it will be like Count = 4
I want to convert this table into a SQL query and I am having a problem converting this Count column that how I am going to calculate this count column in SQL
Does anyone know? please help
step 1 create a temp table with empty column
SELECT * , null as desired_column ,
into #yourTable_t1
FROM #yourTable j;
step 2 create a cursor to calculate your desired_column and update temp_table
begin
declare #row int, #order int, #prod varchar(100), #prod_count int =0 ;
declare prod_cur cursor for
SELECT row_num, MyColumn1,MyColumn2
FROM #yourTable_t1 ;
open prod_cur;
fetch next from prod_cur into #row , #order, #prod;
while (##FETCH_STATUS=0)
begin
set #prod_count= ( select count(MyColumn2) from #yourTable_t1 where
MyColumn2= #prod and ROW_NUM <= #row);
update #yourTable_t1
set desired_column = #prod_count
where ROW_NUM= #row;
fetch next from prod_cur into #row , #order, #prod;
end;
close prod_cur;
deallocate prod_cur;
--select * from #yourTable_t1 order by MyColumn2;
end;
Good Luck!
This can be done using window functions
count(*) over (partition by rege_no order by id) as count
Online example

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

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

Alternative to cursors in SYBASE?

Say i'm dealing with 10 library cards, each card has customer values (eg. member number, member name ...) and I need to update a value for each card.
If i want to grab all ten from the database but only want to update each row one at a time, is there an alternative to a cursor? I know a while loop might work but how would I be able to grab one row every time it loops until I am done with all 10 cards?
Don't need to use cursors. I use this most of the time:
declare #uid int -- this is the type unique index on the table you're updating
-- Copy out the unique ids of the rows you want to update to a temporary table
select uid into #temp from customers -- you can use a where condition here
-- Loop through the rows of the temp table
while exists (select 1 from #temp)
begin
set rowcount 1
select #uid = uid from #temp -- pull one uid from the temp table
set rowcount 0
delete from #temp where uid = #uid -- delete that uid from the temp table
-- Do something with the uid you have
update customers set name = 'Joe Shmoe' where uid = #uid
end
It is possible to loop on the table using a clustered index on a particular column. Because the clustered index arranges the rows in sorted order, it can be used like an index variable of loop.
declare #uid int
select #uid = 0 -- assume the uids in table are > 0
declare #rowsaf int
select #rowsaf = 1
while #rowsaf > 1
begin
set rowcount 1
select #uid = uid from customers where uid > #uid
select #rowsaf = ##rowcount
-- update the row using #uid
end
set rowcount 0
Here is the article that explains it in detail.

Split query result by half in TSQL (obtain 2 resultsets/tables)

I have a query that returns a large number of heavy rows.
When I transform this rows in a list of CustomObject I have a big memory peak, and this transformation is made by a custom dotnet framework that I can't modify.
I need to retrieve a less number of rows to do "the transform" in two passes and then avoid the memory peak.
How can I split the result of a query by half? I need to do it in DB layer. I thing to do a "Top count(*)/2" but how to get the other half?
Thank you!
If you have identity field in the table, select first even ids, then odd ones.
select * from Table where Id % 2 = 0
select * from Table where Id % 2 = 1
You should have roughly 50% rows in each set.
Here is another way to do it from(http://www.tek-tips.com/viewthread.cfm?qid=1280248&page=5). I think it's more efficient:
Declare #Rows Int
Declare #TopRows Int
Declare #BottomRows Int
Select #Rows = Count(*) From TableName
If #Rows % 2 = 1
Begin
Set #TopRows = #Rows / 2
Set #BottomRows = #TopRows + 1
End
Else
Begin
Set #TopRows = #Rows / 2
Set #BottomRows = #TopRows
End
Set RowCount #TopRows
Select * From TableName Order By DisplayOrder
Set RowCount #BottomRows
Select * From TableNameOrder By DisplayOrderDESC
--- old answer below ---
Is this a stored procedure call or dynamic sql? Can you use temp tables?
if so, something like this would work
select row_number() OVER(order by yourorderfield) as rowNumber, *
INTO #tmp
FROM dbo.yourtable
declare #rowCount int
SELECT #rowCount = count(1) from #tmp
SELECT * from #tmp where rowNumber <= #rowCount / 2
SELECT * from #tmp where rowNumber > #rowCount / 2
DROP TABLE #tmp
SELECT TOP 50 PERCENT WITH TIES ... ORDER BY SomeThing
then
SELECT TOP 50 PERCENT ... ORDER BY SomeThing DESC
However, unless you snapshot the data first, a row in the middle may slip through or be processed twice
I don't think you should do that in SQL, unless you will always have a possibility to have the same record 2 times.
I would do it in an "software" programming language, not SQL. Java, .NET, C++, etc...