Iterate through query - sql

I'm trying to iterate through simple query
select a_id, count(ID), TIMESTAMPDIFF(SECOND,MIN(`Time`),MAX(`Time`))
from data
where a_id = 1
This is what I managed to create
DECLARE counter INT DEFAULT 0;
WHILE counter < 10
BEGIN
select a_id, count(ID), TIMESTAMPDIFF(SECOND,MIN(`Time`),MAX(`Time`))
from data
where a_id = counter
SET counter = counter + 1;
END
But I get:
Error occurred during SQL script execution
Reason:
SQL Error [1064] [42000]: (conn=1956) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'DECLARE counter INT DEFAULT 0' at line 1

You don't need a while loop for this. You can do this in a single query. One method is:
with recursive ids as (
select 1 as id
union all
select id + 1
from ids
where id < 10
)
select d.a_id, count(*)
timestampdiff(second, min(d.`Time`), min(d.`Time`))
from ids left join
data d
on d.a_id = ids.id
order by ids.id;
Trying to use a while look is troublesome. Such programming constructs would be in programming blocks. They are designed for stored procedures, functions, and triggers.
I assume that your code is actually over-simplified, because this probably does what you want:
select d.a_id, count(*)
timestampdiff(second, min(d.`Time`), min(d.`Time`))
from data d
where a.id between 1 and 10
group by d.a_id

Use like this
DECLARE #counter INT = 0
WHILE #counter < 10
BEGIN
select a_id, count(ID), TIMESTAMPDIFF(SECOND,MIN(`Time`),MAX(`Time`))
from data
where a_id = #counter
SET #counter = #counter + 1;
END

Related

How can I use dynamic variable #counter in my select query as TOP value

I need a loop in SQL Server 2008 like below:
while #counter < (Select Count(Id) from #Requests)
begin
exec ApplyData(Select TOP 1 Id
from (select TOP #counter Id from #Requests) T
order by Id Desc
)
set #counter = #counter + 1
end
It says the usage of #counter inside the Select query is wrong (syntax error). What is the correct way to use it? How can I fix the syntax error?
Thanks
Use like this
select TOP(#counter)

Looping within SQL(ite) SELECT

The following SQLite query works:
SELECT Name,
(CASE
WHEN P1=1 THEN 1
WHEN P2=1 THEN 2
WHEN P3=1 THEN 3
WHEN P4=1 THEN 4
WHEN P5=1 THEN 5
ELSE NULL
END) AS Col
FROM table
but is there a way to loop then WHEN statements? Following this question and answer I tried:
SELECT Nachname, Vorname,
(CASE
DECLARE #i int = 0
WHILE #i < 5 BEGIN
SET #i = #i + 1
WHEN P#i=1 THEN #i
END
END) AS Col
FROM table
but this didn't work, saying: error in statement: near "#i": syntax error.
For full information I am applying this statement through a sqldf function on R.
SQLite has no mechanism to create column names dynamically.
You have to list all columns by hand, or create the SQL query dynamically from your program.

Loop for each row

I have two tables with FOREIGN KEY([Table_ID])
Columns
ID Table_ID ActiveFlag
1 1 0
2 2 1
3 1 1
4 3 0
Sys_Tables
Table_ID Name
1 Request
2 Plan
3 Contecst
I'm writing a stored procedure that returns any column for each table.
Example Output for values ​​above
--first output table
ID Table_ID ActiveFlag
1 1 0
3 1 1
--second output table
ID Table_ID ActiveFlag
2 2 1
--third output table
ID Table_ID ActiveFlag
4 3 0
My idea is this
Select c.*
from Ccolumns c
inner join Sys_tables t
on t.Table_ID = c.Table_ID and t.Table_ID = #Parameter
My problem, i do't know how to make a loop for each row. I need the best way. Example i can use following loop:
DECLARE #i int = 0
DECLARE #count int;
select #count = count(t.Table_ID)
from Sys_tables t
WHILE #i < #count BEGIN
SET #i = #i + 1
--DO ABOVE SELECT
END
But this is not entirely correct. Example my Sys_tables such data may be
Table_ID Name
1 Request
102 Plan
1001 Contecst
Do You have any idea?
There are couple ways you can achieve that: loops and cursors, but first of all you need to know that it's a bad idea: either are very slow, anyway, here's some kind of loop sample:
declare #row_ids table (
id INT IDENTITY (1, 1),
rid INT
);
insert into #row_ids (rid) select someIdField from SomeTable
declare #cnt INT = ##ROWCOUNT
declare #currentRow INT = 1
WHILE (#currentRow <= #cnt)
BEGIN
SELECT rid FROM #row_ids WHERE id = #currentRow
SET #currentRow = #currentRow + 1
END
I guess you're using SQL Server, right?
Then, you can use a CURSOR as here: How to write a cursor inside a stored procedure in SQL Server 2008

Use top based on condition

I have a parameter in my stored procedure that specifies number of rows to select. (Possible values: 0-100. 0 Means Select All rows)
For example #Rows = 5;
Then I can do this:
Insert into #MyTableVar
Select Top(#Rows) *
from myTable
Now, as I said before if 0 is supplied I need to return all rows.
This is a pseudo-code of what I need:
if (#Rows=0) then select * else select top(#Rows) *
I found out that there's SET ROWCOUNT that accepts 0 to return ALL rows, but I need to do an insert into a table variable which is not supported by ROWCOUNT.
Is it possible to achieve this without dynamic sql?
(I understand that I can write a simple if else statement and duplicate query, but I have pretty complex queries and there are lots fo them, I just want to avoid code duplication)
One way is to just put a big number in:
set #Rows = 5;
declare #RowsToUse = (case when #Rows = 0 then 1000000000 else #Rows end);
select top(#RowsToUse) * from myTable
First of all, you are missing the ORDER BY clause, since you are using TOP. You could do this:
SET #Rows = 5;
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(ORDER BY Id) --put the right order here
FROM myTable
)
INSERT INTO #MyTableVar
SELECT YourColumns
FROM CTE
WHERE RN <= #Rows OR #Rows = 0

sql setting xml property through a loop

trying desperately to combine 2 simple answers into specifically what i need.
sql loop and set properties
sql to set an xml value
SET #I := 0;
SELECT *,
#I := #I + 1
SET xml = UpdateXML(xml,'comic/pageNumber', '<pageNumber>'.#I.'</pageNumber>')
FROM `comics`
ORDER BY ExtractValue(xml,'comic/pageNumber')+100000 ASC
this is as close as i have come, i know the SELECT / ORDER BY works separate from trying to SET the xml property.
side note: the +100000 is a work
around to treat the value as numeric
for sorting. otherwise 11 < 2 but
100011 > 100002
i have also tried this
SET #I := 0;
UPDATE comics,
#I := #I + 1 AS newPageNumber
SET xml = UpdateXML(xml,'comic/pageNumber', '<pageNumber>'.#I.'</pageNumber>')
WHERE 1
ORDER BY ExtractValue(xml,'comic/pageNumber')+100000 ASC
i think i just don't know how to combine the SELECT and UPDATE
UPDATE comics
inner join (
select c.id, #row:=#row+1 rownum
from (select #row:=0) X cross join comics c
ORDER BY ExtractValue(xml,'comic/pageNumber')*1.0) Y on Y.id=comics.id
SET xml = UpdateXML(xml,
'comic/pageNumber',
concat('<pageNumber>',Y.rownum,'</pageNumber>'))
;
Based on this test schema and data
create table comics (id int auto_increment primary key, xml text);
insert comics select null, '<comic><name>test1</name><pageNumber>7</pageNumber><content>page 5 con</content></comic>';
insert comics select null, '<comic><name>test1</name><pageNumber>3</pageNumber><content>page 6 con</content></comic>';
insert comics select null, '<comic><name>test1</name><pageNumber>5</pageNumber><content>page 7 con</content></comic>';