SELECT INTO #var in Stored Procedure not working [duplicate] - mysql

Let's say a have a stored procedure SetCustomerName which has an input parameter Name, and I have a table customers with column Name.
So inside my stored procedure I want to set customer's name. If I write
UPDATE customers SET Name = Name;
this is incorrect and I see 2 other ways:
UPDATE customers SET Name = `Name`;
UPDATE customers SET customers.Name = Name;
First one works, but I didn't find in documentation that I can wrap parameters inside ` characters. Or did I miss it in the documentation (link is appreciated in this case).
What other ways are there and what is the standard way for such a case? Renaming input parameter is not good for me (because I have automatic object-relational mapping if you know what I mean).
UPDATE:
So, there is a link about backticks (http://dev.mysql.com/doc/refman/5.0/en/identifiers.html) but it's not explained deep enough how to use them (how to use them with parameters and column names).
And there is a very strange thing (at least for me): You can use backticks either way:
UPDATE customers SET Name = `Name`;
//or
UPDATE customers SET `Name` = Name;
//or even
UPDATE customers SET `Name` = `Name`;
and they all work absolutely the same way.
Don't you think this is strange? Is this strange behavior explained somewhere?

Simplest way to distinguished between your parameter and column (if both name is same) is to add table name in your column name.
UPDATE customers SET customers.Name = Name;
Even you can also add database prefix like
UPDATE yourdb.customers SET yourdb.customers.Name = Name;
By adding database name you can perform action on more than 1 database from single store procedure.

I think that your first example is actually backwards. If you're trying to set the "Name" column to the "Name" input parameter, I believe it should be:
UPDATE customers SET `Name` = Name;
And for the second example, you can set table aliases the same way that you do in all other statements:
UPDATE customers AS c SET c.Name = Name;

Not necessarily correct, but a fair way to better argument/parameter management, as well readability with easier understanding, especially while working with the SQL;
DROP PROCEDURE IF EXISTS spTerminalDataDailyStatistics; DELIMITER $$
CREATE PROCEDURE spTerminalDataDailyStatistics(
IN TimeFrom DATETIME,
IN DayCount INT(10),
IN CustomerID BIGINT(20)
) COMMENT 'Daily Terminal data statistics in a date range' BEGIN
# Validate argument
SET #TimeFrom := IF(TimeFrom IS NULL, DATE_FORMAT(NOW(), '%Y-%m-01 00:00:00'), TimeFrom);
SET #DayCount := IF(DayCount IS NULL, 5, DayCount);
SET #CustomerID := CustomerID;
# Determine parameter
SET #TimeTo = DATE_ADD(DATE_ADD(#TimeFrom, INTERVAL #DayCount DAY), INTERVAL -1 SECOND);
# Do the job
SELECT DATE_FORMAT(TD.TerminalDataTime, '%Y-%m-%d') AS DataPeriod,
COUNT(0) AS DataCount,
MIN(TD.TerminalDataTime) AS Earliest,
MAX(TD.TerminalDataTime) AS Latest
FROM pnl_terminaldata AS TD
WHERE TD.TerminalDataTime BETWEEN #TimeFrom AND #TimeTo
AND (#CustomerID IS NULL OR TD.CustomerID = #CustomerID)
GROUP BY DataPeriod
ORDER BY DataPeriod ASC;
END $$
DELIMITER ;
CALL spTerminalDataDailyStatistics('2021-12-01', 2, 1801);

Using backticks in MySQL query syntax is documented here:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
So yes, your first example (using backticks) is correct.

Here is the link you are asking for:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
The backticks are called "identifier quote" in MySql

Related

Update query is not working in my sql procedure.why?

CREATE PROCEDURE Sp_IU_Group(
GID int,
GroupName nvarchar(200),
UserID int,
Status int
)
BEGIN
IF GID=0 THEN
Insert into tblGroup (GroupName,UserID,Status)
values (GroupName,UserID,Status);
else
update tblGroup set GroupName=GroupName,UserID=UserID,Status=Status WHERE GID=GID;
END IF;
END
This query:
update tblGroup set GroupName=GroupName,UserID=UserID,Status=Status WHERE GID=GID
Will update every record in the table... to itself. This matches every record, because this is always true:
WHERE GID=GID
And this updates a value to itself:
GroupName=GroupName
The problem is that you're using the same names for multiple things. Give things different names. Something as simple as this:
CREATE PROCEDURE Sp_IU_Group(
GIDNew int,
GroupNameNew nvarchar(200),
UserIDNew int,
StatusNew int
)
(Or use any other standard you want to distinguish the variables from the database objects, such as prepending them with a special character like an #.)
Then the query can tell the difference:
update tblGroup set GroupName=GroupNameNew,UserID=UserIDNew,Status=StatusNew WHERE GID=GIDNew
(Modify the rest of the stored procedure for the new variable names accordingly, of course.)
Basically, as a general rule of thumb, never rely on the code to "know what you meant". Always be explicit and unambiguous.

Mysql search with ignore special characters

I have a table 'products' which has a column partnumber.
I want to ignore special characters from record while searching.
Suppose i have following 5 records in partnumber:
XP-12345
MV-334-3454
XP1-5555
VX-AP-XP-1000
VT1232223
Now, If i try to search "XP1", then Output should be come like following records
XP-12345
XP1-5555
VX-AP-XP-1000
How to write mysql query for this ?
You can achieve this functionality using concat() function. As I can review your and Jorden answer comment that you want to search string XP1 with ignore special charecter like -,_,# .
So you can use this query
SELECT partnumber FROM products
WHERE partnumber LIKE concat('%XP','_','1%')
OR partnumber LIKE '%XP1%';;
Note: Require output you can check on SQLFIDDLE and You can adjust query based on your additional requirement.
Define a MySQL function which strips the symbols from a provided string.
DELIMITER //
CREATE FUNCTION STRIP_SYMBOLS(input VARCHAR(255))
RETURNS VARCHAR(255) DETERMINISTIC NO SQL
BEGIN
DECLARE output VARCHAR(255) DEFAULT '';
DECLARE c CHAR(1);
DECLARE i INT DEFAULT 1;
WHILE i < LENGTH(input) DO
SET c = SUBSTRING(input, i, 1);
IF c REGEXP '[a-zA-Z0-9]' THEN
SET output = CONCAT(output, c);
END IF;
SET i = i + 1;
END WHILE;
RETURN output;
END//
DELIMITER ;
Then select the records from your table where the partnumber with the symbols stripped contains XP1:
SELECT * FROM products WHERE STRIP_SYMBOLS(partnumber) LIKE '%XP1%';
-- Returns: XP-12345, XP1-5555, VX-AP-XP-1000
This might be painfully slow if your table is large. In this case, look into generated columns (if you have MySQL 5.7.6 or higher) or creating a trigger (if an earlier version) to keep a column in your table updated with the partnumber with symbols stripped.
You need to use REGEXP to allow for containing searches.
EX:
SELECT partnumber
FROM partnumber_tbl
WHERE name REGEXP '[XP1]\-';
This will let it search the database to find anything containing X,P,1.
Here is a live example.
And regexp info for you to look more into. Official docs, I hate reading them, especially oracles.
.......
You could do something like:
SELECT partnumber
FROM products
WHERE REPLACE(partnumber, "_", "")) LIKE '%XP1%');

Can I specify a query as a field's default value?

I mean something like:
create table Measures (
id_user int,
date timestamp,
measure_1 double default 'select measure_1 from Measures where data = '**/**/****'',
measure_2 double default 'select measure_1 from Measures where data = '**/**/****'');
In this way I insert the value of the last measure saved in the db..
Is it possible?
Not directly:
11.7 Data Type Default Values
... the default value must be a constant; it cannot be a function or an expression.
You'll have to do this on application level, or in a trigger as suggested by #Timekiller.
You can do that via a before-insert trigger.
Check if NEW.measure_1 is null, and if it is, then perform select and store results.
UPD:
Right, I was in a bit of a hurry yesterday, and forgot to give an example later. Trigger is a good replacement for complex default value - it will work transparently, will look just like the default value from database user standpoint, and you won't have to do anything on the application level, since triggers are stored in the database itself. It will look something like this:
CREATE TRIGGER `measures_bi_trigger` BEFORE INSERT ON `Measures`
FOR EACH ROW BEGIN
if NEW.measure_1 is null then
SET NEW.measure_1 = (select measure_1 from Measures where ... limit 1);
end if;
if NEW.measure_2 is null then
SET NEW.measure_2 = (select measure_2 from Measures where ... limit 1);
end if;
END
It's not exactly clear what should be in your where condition, so you'll have to substitute ... yourself. Note that your query should return exactly one row, so either use an aggregate function like MAX or order by ... limit 1. If your query returns no rows, NULL will be inserted.

Add multiple tags to table

I have a table tags in database and I want create a query that was based on add values if not exist name of tag, next selected ID and if name exist selected tag ID
I creat a simply code:
DELIMITER $$
USE `cc`$$
DROP FUNCTION IF EXISTS getTagId$$
CREATE FUNCTION getTagId (tag CHAR(20)) RETURNS INT CHARSET utf-8
BEGIN
DECLARE id INT
set #id = (select id from tags where name = #tag)
if (#id is null) then
insert into tags(name) values(#tag)
set #id = (select last_insert_id())
end if
SELECT #id
END
delimiter;
But this code doesn't work (This is my first function in MySQL).
I want add to database more tags then 10 in single query, do you have any ideas on how to optimize?
But probably my old answer is useless. The real question is: is this Stored Function really needed? I guess you are trying to do this just to avoid duplicates.
To reach the same goal:
add a UNIQUE index to tags.name
use INSERT IGNORE (no error if that tag already exists)
You should add a $$ before last line.
And also, you forgot a lot of ;
Returning a number and specifying the charset is absurd, and probably is a syntax error.
Drop all lines with #id and simply add RETURN last_insert_id();
IF NOT EXISTS ((select id from tags where name = tag)) THEN
(also note that I removed # from tag!)
Probably there are more errors, but star with these :)

MySQL : When stored procedure parameter name is the same as table column name

Let's say a have a stored procedure SetCustomerName which has an input parameter Name, and I have a table customers with column Name.
So inside my stored procedure I want to set customer's name. If I write
UPDATE customers SET Name = Name;
this is incorrect and I see 2 other ways:
UPDATE customers SET Name = `Name`;
UPDATE customers SET customers.Name = Name;
First one works, but I didn't find in documentation that I can wrap parameters inside ` characters. Or did I miss it in the documentation (link is appreciated in this case).
What other ways are there and what is the standard way for such a case? Renaming input parameter is not good for me (because I have automatic object-relational mapping if you know what I mean).
UPDATE:
So, there is a link about backticks (http://dev.mysql.com/doc/refman/5.0/en/identifiers.html) but it's not explained deep enough how to use them (how to use them with parameters and column names).
And there is a very strange thing (at least for me): You can use backticks either way:
UPDATE customers SET Name = `Name`;
//or
UPDATE customers SET `Name` = Name;
//or even
UPDATE customers SET `Name` = `Name`;
and they all work absolutely the same way.
Don't you think this is strange? Is this strange behavior explained somewhere?
Simplest way to distinguished between your parameter and column (if both name is same) is to add table name in your column name.
UPDATE customers SET customers.Name = Name;
Even you can also add database prefix like
UPDATE yourdb.customers SET yourdb.customers.Name = Name;
By adding database name you can perform action on more than 1 database from single store procedure.
I think that your first example is actually backwards. If you're trying to set the "Name" column to the "Name" input parameter, I believe it should be:
UPDATE customers SET `Name` = Name;
And for the second example, you can set table aliases the same way that you do in all other statements:
UPDATE customers AS c SET c.Name = Name;
Not necessarily correct, but a fair way to better argument/parameter management, as well readability with easier understanding, especially while working with the SQL;
DROP PROCEDURE IF EXISTS spTerminalDataDailyStatistics; DELIMITER $$
CREATE PROCEDURE spTerminalDataDailyStatistics(
IN TimeFrom DATETIME,
IN DayCount INT(10),
IN CustomerID BIGINT(20)
) COMMENT 'Daily Terminal data statistics in a date range' BEGIN
# Validate argument
SET #TimeFrom := IF(TimeFrom IS NULL, DATE_FORMAT(NOW(), '%Y-%m-01 00:00:00'), TimeFrom);
SET #DayCount := IF(DayCount IS NULL, 5, DayCount);
SET #CustomerID := CustomerID;
# Determine parameter
SET #TimeTo = DATE_ADD(DATE_ADD(#TimeFrom, INTERVAL #DayCount DAY), INTERVAL -1 SECOND);
# Do the job
SELECT DATE_FORMAT(TD.TerminalDataTime, '%Y-%m-%d') AS DataPeriod,
COUNT(0) AS DataCount,
MIN(TD.TerminalDataTime) AS Earliest,
MAX(TD.TerminalDataTime) AS Latest
FROM pnl_terminaldata AS TD
WHERE TD.TerminalDataTime BETWEEN #TimeFrom AND #TimeTo
AND (#CustomerID IS NULL OR TD.CustomerID = #CustomerID)
GROUP BY DataPeriod
ORDER BY DataPeriod ASC;
END $$
DELIMITER ;
CALL spTerminalDataDailyStatistics('2021-12-01', 2, 1801);
Using backticks in MySQL query syntax is documented here:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
So yes, your first example (using backticks) is correct.
Here is the link you are asking for:
http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
The backticks are called "identifier quote" in MySql