I have the error : Result consisted of more than one row but i can't find out it.
The entry id_user has only one record in its table.
The procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `delete_user_deep`(id_user int(11))
BEGIN
declare nome_loc varchar(45);
declare cognome_loc varchar(45);
select nome,cognome
into nome_loc,cognome_loc
from user
where id_user=id_user;
delete from Radius.radcheck where username in (
select mac_address from machine where id_user =id_user);
delete from Radius.radreply where username in (
select mac_address from machine where id_user =id_user);
delete from machine_ip where id_machine in (
select id_machine from machine where id_user=id_user);
delete from machine where id_user = id_user;
delete from document where id_user=id_user;
delete from user where id_user=id_user;
insert into log_generic values(
NULL,
'USER',
'Delete User Deep',
(select concat ('User: ',id_user,' Name: ',cognome_loc,' Prename: ',nome_loc)),
now());
END
The problem is in this statement:
select nome,cognome
into nome_loc,cognome_loc
from user
where id_user=id_user;
This will return an error if there is more than one row. The error is documented here.
This is caused because the parameter name is the same as the column name. The id_user is referring to the column on both sides of the comparison.
The query should look like:
select nome, cognome
into nome_loc, cognome_loc
from user
where id_user = param_id_user;
Always prefix parameter and variable names with something to distinguish them from column names.
Related
I have two tables, tableA and tableB. They are connected by a foreign key on their IDs (ATableID, BTableID).
TableB has a stored procedure that allows rows to be archived, It has 2 columns in it named Available_Days and Available_Night. In TableA
There is also columns Available_Days and Available_Night, which are joined to tableB by a left join. If there is data in those columns in TableA, you must not be able to archive the row in TableB.
This is the stored procedure currently, I need help implementing the criteria explained above.
#BTableID VARCHAR(500) = '',
#UserArchived INT = 0
AS
DECLARE #Local BTableID VARCHAR(500)
DECLARE #LocalUserArchived INT
DECLARE #LocalSql NVARCHAR(500)
set #Local BTableID = #BTableID;
set #LocalUserArchived = #UserArchived;
set #LocalSql = 'UPDATE tableB
SET DateArchived = GETDATE(),
UserArchived = '+CAST(#UserArchived as NVARCHAR)+'
WHERE BTableID IN ('+# BTableID +')'
I am also open for any suggestions if the current direction isn't wise.
For full context, this stored procedure will be used in php Laravel framework where a user will be able to delete a row(TableB), unless that rows information is referenced elsewhere(TableA), in which case, they will be prompted to update the other table before attempting to delete again.
Once again, the desired result is to prevent archiving/soft deleting (preventing setting DateArchived = GETDATE()) a row if its information is referenced in another table.
UPDATE:
I've made two possible adjustments (currently unable to test them as I'm not able to access the db at the moment.)
set #LocalSql = 'UPDATE BTable
SET DateArchived = GETDATE(),
UserArchived = '+CAST(#UserArchived as NVARCHAR)+'
WHERE BTableID IN ('+#BTableID+')
WHERE NOT EXISTS (
SELECT FROM ATable at
WHERE tp.ATable_FK = tp.BTableID)'
and
set #LocalSql = 'UPDATE tableB
SET DateArchived = GETDATE(),
UserArchived = '+CAST(#UserArchived as NVARCHAR)+'
WHERE tableBID IN ('+#tableBID+')
LEFT JOIN tableA cm ON cm.tableAID = tp.tableBID
WHERE cm.tableAID IS NULL’
I'm not able to test them at this time but will update this post to let you know if either did the job. If you have any suggestions on improvements please leave a comment or answer. :)
SOLUTION:
I figured out a very simple solution to solve my issue. I forgot all about the archive/soft delete stored procedures and created two stored procedures for table A and table B which selects one record from the table. ie :
#TableAIB int
AS
SELECT
TableBID,
TableBDescription,
FROM TableB
WHERE TableBID = #TableBID
RETURN ##ERRO
and
GO
#TableAID int
AS
SELECT
TableAID,
TabelADescritption
FROM TableA
WHERE TableAID = #TableAID
RETURN ##ERROR
GO
these two two tables are connected via a foreign key(on tableAID and tableBID).
in the controller I then did this:
public function archive(int $id)
{
$tableA = tableA::find($id);
$tableB = tableB::find($id);
if ($tableA->TableAID == $tableB->TableBID){
return redirect()->route(‘myPage.index')
->with('warning', ’This can not be archived, it is being used in another row. ');
}
}
This is essentially saying that if the two stored procedure's ID's match, redirect to the index page with a warning.
In my php code, I have a Mysql query:
SELECT COUNT(*)
to see if the record already exists, then if it doesn't exist I do an:
INSERT INTO <etc>
But if someone hits reload with a second or so, the SELECT COUNT(*) doesn't see the inserted record.
$ssql="SELECT COUNT(*) as counts FROM `points` WHERE `username` LIKE '".$lusername."' AND description LIKE '".$desc."' AND `info` LIKE '".$key."' AND `date` LIKE '".$today."'";
$result = mysql_query($ssql);
$row=mysql_fetch_array($result);
if ($row['counts']==0) // no points for this design before
{
$isql="INSERT INTO `points` (`datetime`,`username`,`ip`,`description`,`points`,`info`, `date`,`uri`) ";
$isql=$isql."VALUES ('".date("Y-m-d H:i:s")."','".$lusername."',";
$isql=$isql."'".$_SERVER['REMOTE_ADDR']."','".$desc."','".$points."',";
$isql=$isql."'".$key."','".$today."','".$_SERVER['REQUEST_URI']."')";
$iresult = mysql_query($isql);
return(true);
}
else
return(false);
I was using MyISAM database type
Instead of running two seperate queries just use REPLACE INTO.
From the documentation:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
For example if your key field is id then:
REPLACE INTO my_table SET id = 4 AND other_field = 'foobar'
will insert if there is no record with id 4, or if there is then it will replace the other_field value with foobar.
I have an identity column (id) that auto-increments.
id|name|image_path
I want to know if there is some way using mysql, to use the newly inserted id in the image_path.
For example if a new row is inserted and got the id 2 I want the image_path to be "/images/2.png".
Or do I have to use the traditional way, by inserting and then fetching this ID then updating the entry?
My opinion is that it is impossible to do with one query. You won't know new autoincrement value until row will be inserted. Still you can write 1 query to achieve what you want (actually 2 queries would be executed):
insert into `t`(`id`, `name`, `image_path`)
values(
(SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE `table_name` = 't'),
'1234',
concat(
'/images/',
(SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE `table_name` = 't'),
'.png'
)
)
Anyway much safer would be:
START TRANSACTION;
set #c = (select ifnull(max(`id`),0) + 1 from `t`);
insert into `t`(`id`, `name`, `image_path`) values (#c,'123',concat('/images/',#c,'.png'));
COMMIT;
Yes, it is possible with oracle. We have dynamic sql feature.
have tried the below.
Created a sequence and then created a procedure which takes id as input and creates an insert statement dynamically which will fulfill your requirement.
create sequence seq1 start with 1;
create table image1(id1 number,image varchar2(50));
create or replace procedure image1_insert(id1 in number)
as
sql_stmt varchar2(50);
image_path varchar2(50);
begin
sql_stmt:='insert into image1 values(:1,:2)';
image_path:='/image/'||id1||'.png';
execute immediate sql_stmt using id1,image_path;
end;
begin
image1_insert(seq1.nextval);
end;
id image
4 /image/4.png
5 /image/5.png
select *from image1;
I have table status and status_stage . After insert in status table, I want to add it to the status_stage table. I have this procedure:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `addStatus`(status VARCHAR(45), stage int (8))
BEGIN
DECLARE status_id INT DEFAULT NULL;
INSERT INTO status (status)
VALUES (status);
SELECT id INTO status_id FROM status WHERE status = status;
INSERT INTO stage_status (stage,status)
VALUES (stage,id);
END
And I call that function with this:
$result= $this->db->query("call addStatus('$status', $stage)");
return ($result->num_rows()>0);
When I tried it it gives me this Error:
Result consisted of more than one row
Your SELECT ... INTO statement got more than one result because of your WHERE clause with status = status, this equals forever
you need to change the param name to distinguish it from the table column name (eg. status_param)
How would this be done? I would like to search the database row by row. I might even print out the entire list of the database row by row. But I would also like to show record 1400 for example and determine the info on that row - such as name, gender and country.
Is it possible to use the rownum function to get this done? Or would I need to use a where in the query? But even so how would I determine the row number? Thanks.
Make one column as ID, make it PK and auto_increment. Then your query shell be something like this for #1400 row:
$pdo
->prepare(
"SELECT `name`, `gender`, `country`
FROM `foo_table` WHERE `id` = :id"
)
->execute([':id' => 1400]);
You can use user defined variables to get your rownumber in MySQL
set #nr = 0;
Now you can use this variable (same connection!) in your query
SELECT
#nr := (#nr + 1) rownumber,
*
FROM
table
see: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
do your select and add
LIMIT n,1
this will skip to n-th element(1400) and show just one result