I'm trying to perform an insert query into a loop from a select results.
The problem is when I want to retrieve only one result from a select query that works correctly
but when the select query retrieve more than one result that doesn't work.
Is there an issue with the GROUP_CONCAT function ? How can I do in order fix the issue ?
I let you the code snippet here :
BEGIN
SELECT idJour INTO #idJour FROM `jour` WHERE JourSemaine = DayWeek;
SELECT GROUP_CONCAT(idTrancheH) AS result FROM tranchehoraire WHERE TrancheH BETWEEN heureDebut AND heureFin;
loop_label : loop
INSERT INTO `horaire` (`idEmployé`, `idJour`, `idTrancheH`) VALUES
(idEmployee,#idJour, #idTrancheH);
SET heureDebut = ADDTIME(heureDebut ,'0:30:00.00');
IF heureDebut <= TIME(heureFin) THEN
ITERATE loop_label;
ELSE
LEAVE loop_label;
END IF;
END LOOP;
RETURN heureDebut;
END
Thanks a lot
Related
I need to update a table based on the result of a subquery that brings more than 1 value, but with the query below I get the error return "Subquery returns more than 1 row". I would like to know if it is possible to make a "loop" to update the values with each result presented in my subquery below.
Complete Query
UPDATE estoque_tamanhos tam
SET tam.qtde = tam.qtde - IF(NEW.tipo = 'K', NEW.qtde_prod * NEW.qtde_lote, NEW.qtde_prod)
WHERE tam.estoques_id = (SELECT estoques_id
FROM combo_estoque
WHERE produtos_id = NEW.produtos_id)
AND UPPER(tam.tamanho) = UPPER(NEW.tamanho_prod);
Subquery that returns 2 or more values.
SELECT estoques_id FROM combo_estoque WHERE produtos_id = NEW.produtos_id
Result
produtos_id
estoques_id
246
54
246
207
In the ideal scenario, my query would execute the first value, after the second ... third ... without repeating the previous ones.
You should create a stored procedure using Cursors to iterate each result of your query.
CREATE PROCEDURE UPDATING_ROWS(PRODUTO_ID INT, qtde_prod INT, qtde_lote INT, TIPO INT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE estoque_;
DECLARE cursor FOR SELECT estoques_id FROM combo_estoque WHERE produtos_id = NEW.produtos_id) AND UPPER(tam.tamanho) = UPPER(NEW.tamanho_prod)
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO estoque_;
IF done THEN
LEAVE read_loop;
END IF;
UPDATE estoque_tamanhos tam SET tam.qtde = tam.qtde - IF(TIPO = 'K',
qtde_prod * qtde_lote, qtde_prod)
WHERE tam.estoques_id = estoque_;
END LOOP;
END
You have to create a stored procedure like this to iterate each result of your select query. You can read more about this in this link
I have a query that gives output "OK".
I want to use that result from the query to run another query.
If result is OK then don't run.
If it is ERROR, then run.
The queries are slow and I don't want to execute the second query if the result is OK. The second query checks what is wrong.
How I can do this? I checked in the Internet but I don't know if there is such function and it's name. I don't want to use nested queries or WITH expressions
Thanks!
Use Try and Catch to error handling and do what you want to execute as per below:
If Query 1 is executed then query 2 skip otherwise execute query 2 if any error in query 1:
Begin Try
--Query 1
End Try
Begin Catch
-- Query 2
End catch
you can put result of the query into variable and then check it using IF...ELSE
declare #test varchar(10) = 'ok';
if #test != 'ok'
begin
--query if not 'ok'
end
else
begin
--query if 'ok', or you can remove `else` at all if not required
end
DEMO
Well, you can create a variable in which you store the result of a function that returns 'OK' or 'KO' (How to create a function with SQL Server).
Then you can use an IF statement where you execute different queries
IF statement SQL Server.
This could be an idea.
Capture result set into a variable. Also ensure your condition returns one or other and only one column
I have added a sample query
declare #output VARCHAR(10)
SET #OUTPUT =
--sample query
(select case when SUM(s.SellingValue) = SUM(h.SellingValue) then 'OK' ELSE 'ERROR' END OUTPUT
from Missing_Sales s inner join Missing_Sales_TH h on s.Branch_no = h.Branch_no and s.date = h.Date)
BEGIN
IF #output = 'OK'
--sample query
SELECT * FROM Missing_Sales
ELSE
--sample query
SELECT * FROM Missing_Sales_TH
END
After creating trigger It started to displaying the Invalid use of group function error on update query.
Trigger:
CREATE TRIGGER header_true BEFORE UPDATE
ON category
FOR EACH row
begin
IF new.Header = 'True' THEN
SET new.H_order = max(old.H_order) + 1;
end IF;
end
Update Query:
UPDATE `category` SET `Header` = 'True' WHERE `category`.`ID` = 23
Anyone can please help me How can I resolve this issue?
You can try this solution for your problem :
MAX function is used to return the maximum value of an expression in a SELECT statement. MAX function is not possible without SELECT statement.
CREATE TRIGGER header_true BEFORE UPDATE
ON category
FOR EACH row
begin
IF new.Header = 'True' THEN
SET new.H_order = (select max(H_order) + 1 from category) + 1;
end IF;
end
I hope it will help.
This below code is a cursor in PostgreSQL 9.0. I want to fetch my records by joining more than one table and i am getting JSON data from that join.
So I want to loop those records and parse that json using query something like
SELECT "Dump"->'activities-steps'->0->'value' as "steps"
FROM "ActivitySessionDump" where "Id"=42594321345021288
then i have to get data from this query and insert to some other table like
insert to table name (key,value);
So i prepared one readonly cursor to achieve this task
begin work;
DECLARE
sessionids INSENSITIVE no scroll CURSOR FOR
SELECT asn."Id",asn."UserId",asn."ActivityId",ad."Dump"
FROM "ActivitySession" as asn inner join "ActivitySessionDump" as ad
on asn."Id"=ad."ActivitySessionId"
where asn."CreatedAt" between now() - interval '5 hours' and now() and asn."ActivityId"=1
for read only;
---- i want her loop should start and i will parse a json Dump by executing query--------
--------insert record to another table---------------
---end loop-----------
FETCH next FROM sessionids;
CLOSE sessionids;
COMMIT WORK;
Any help really appreciated.Thanks
Since you cannot loop in SQL, you'll have to use PL/pgSQL, for example with a DO statement.
In your case, that could look like this:
DO
$$DECLARE
asn_id ...;
asn_userid ...;
...
c refcursor;
BEGIN
/* assign the SQL cursor to the refcursor variable */
c := 'sessionids';
LOOP
FETCH c INTO asn_id, asn_userid, ...;
IF NOT FOUND THEN EXIT; END IF;
/* process the result row */
END LOOP;
END;$$;
Of course it is a bit awkward to declare a cursor in SQL and use it in PL/pgSQL.
It might be better to put the statement in a FOR loop like this:
FOR asn_id, asn_userid, ... IN
SELECT ...
LOOP
/* process the result row */
END LOOP;
Maybe you could even squeeze the whole thing into a single INSERT statement, that would be most efficient:
INSERT INTO ...
(SELECT ...);
As far as I can tell, the loop or function is unnecessary. It can be replaced with a simple query using string aggregation:
SELECT string_agg("Dump"->'activities-steps'->0->'value', ',') as steps
FROM "ActivitySessionDump" d
WHERE d."ActivitySessionId" IN (SELECT asn."Id"
FROM "ActivitySession" as asn
join "PersonDataSource" as pd on pd."UserId" = asn."UserId"
where asn."CreatedAt" between now() - interval '5 days' and now()
and asn."ActivityId" = 1
and pd."DataSourceId" = 1);
Unrelated, but: you should really avoid those dreaded quoted identifiers
here is the code for my question and i am unable to
EXECUTE 'SELECT rec."Dump"::json#>''{activities-steps,0}''->>''value'' as steps ' INTO jsonrec; line;
SELECT '{"activities-steps":[{"dateTime":"2016-10-17","value":"4023"}]}'::json#>'{activities-steps,0}'->>'value' as steps;
where as i can execute this code in console.
but inside function i cant.
CREATE OR REPLACE FUNCTION ThirdPartyDataParse()
RETURNS text AS $$
DECLARE
sessionid NO SCROLL CURSOR FOR SELECT asn."Id",asn."UserId",asn."ActivityId",pd."DataSourceId",ad."Dump"::TEXT
FROM "Development"."ActivitySession" as asn inner join "Development"."PersonDataSource" as pd on pd."UserId" = asn."UserId" inner join "Development"."ActivitySessionDump" as ad
on asn."Id"=ad."ActivitySessionId" where asn."CreatedAt" between now() - interval '5 days' and now() and asn."ActivityId"=1 and pd."DataSourceId"=1 for read only;
titles TEXT DEFAULT '';
rec record;
jsonrec record;
BEGIN
OPEN sessionid;
loop
FETCH sessionid INTO rec;
--raise notice '%d',rec."UserId";
if not found then
exit ;
end if;
EXECUTE 'SELECT rec."Dump"::json#>''{activities-steps,0}''->>''value'' as steps ' INTO jsonrec;
titles := titles || ',' || jsonrec."steps";
end loop;
return titles;
END;
$$ LANGUAGE plpgsql;
I have this trigger. If the incoming log agrees with input filter, than is not saved into database. But, I want to keep number of "hits" of each Primitive_filter. I have a column named hit_rate, which is int(30). Is there some way how to do that? Maybe specific error? Or sth else? Thx for help.
UPDATE Primitive_filters SET hit_rate = hit_rate + 1 where Primitive_filters.id = ???;
trigger
delimiter //
CREATE TRIGGER inputFilter
before insert
on Logs
for each row
begin
declare msg varchar(255);
IF (SELECT COUNT(*) FROM Primitive_filters, Primitive_in_filter, Filters WHERE
Filters.name = "input" AND Filters.id = Primitive_in_filter.id_filter AND Primitive_in_filter.id_primitive = Primitive_filters.id AND
(Primitive_filters.id_host LIKE CONCAT('%',(SELECT host FROM Hosts WHERE id = new.id_host),'%') OR Primitive_filters.id_host IS NULL) AND
(Primitive_filters.facility LIKE CONCAT('%',new.facility,'%') OR Primitive_filters.facility IS NULL) AND
(Primitive_filters.priority LIKE CONCAT('%',new.priority,'%') OR Primitive_filters.priority IS NULL) AND
(Primitive_filters.program LIKE CONCAT('%',new.program,'%') OR Primitive_filters.program IS NULL) AND
(new.msg REGEXP Primitive_filters.msg OR Primitive_filters.msg IS NULL)) > 0 THEN CALL raise_error; END IF;
END //
delimiter ;
This is NOT the answer to your question.
It's only a hint how to fix a potentially serious performance problem in your code.
Don't use this:
IF (SELECT COUNT(*) FROM ... giant query ...) > 0
THEN CALL raise_error;
END IF;
Use this instead:
IF EXISTS (SELECT 1 FROM ... giant query ...)
THEN CALL raise_error;
END IF;
The former condition calculates a count ... it must read all rows returned by the query
If the query returns billion rows, it must reads them all --> because you asked give me a count of rows.
Then, after the query return the count, there is a check: if the query returns at least one row, then do something.
The latter condition stops executing the query when the query returns first row, saving time and resources.