SQL user defined function not run - mysql

I have situation where I want to generate invoice_id sequential for different product for multiple cities. I want to get generated invoice id according to different product and city.
My table temp look like
id |order_id |product|city|invoice_id
1 | 123 | 1 | 1 | FPU1
2 | 124 | 6 | 1 | PPU1
I want to get next invoice_id for product 1 and city 1 is FPU2.
For product 1 and city 2 is FBN1,product 6 and city 1 is PPU2 and so on ....
I create function but not run.Is anything wrong in function?
CREATE function generate(p_id INT, c_id INT)
returns VARCHAR(50)
BEGIN
-- DECLARE v_new_id VARCHAR(50);
SELECT Concat(( CASE
WHEN t.product = 1 THEN "f"
WHEN t.product = 6 THEN "p" end ),
c.city_name, Cast(RIGHT(t.invoice, Length(t.invoice) - 3) AS UNSIGNED) + 1
) v_new_id
FROM temp AS t
JOIN city c
ON c.city_id = t.city
WHERE t.product = p_id
AND t.city = c_id;
RETURN( v_new_id );
end;
Get syntax error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 15
###Line 15 is AND t.city = c_id;

Need to set delimiters .
Thanks #P.Salmon for valuable comment and link
For set delimiter manually follow
For phpmyadmin user follow this link

Related

Is there a way to restart autoincrement id from 1, when session_id changes? (without using stored procedures ecc..) [duplicate]

I'm working on some legacy code/database, and need to add a field to the database which will record a sequence number related to that (foreign) id.
Example table data (current):
ID ACCOUNT some_other_stuff
1 1 ...
2 1 ...
3 1 ...
4 2 ...
5 2 ...
6 1 ...
I need to add a sequenceid column which increments separately for each account, achieving:
ID ACCOUNT SEQ some_other_stuff
1 1 1 ...
2 1 2 ...
3 1 3 ...
4 2 1 ...
5 2 2 ...
6 1 4 ...
Note that the sequence is related to account.
Is there a way I can achieve this in SQL, or do I resort to a PHP script to do the job for me?
TIA,
Kev
Create a trigger:
CREATE TRIGGER trg_mytable_bi
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
DECLARE nseq INT;
SELECT COALESCE(MAX(seq), 0) + 1
INTO nseq
FROM mytable
WHERE account = NEW.account;
SET NEW.seq = nseq;
END;
The question is tagged as "mysql", so yes, MySQL's auto_increment can create groupwise sequential ids.
see http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html:
For MyISAM and BDB tables you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.
edit: example php script (using PDO, but it's the same game with the php-mysql module)
$pdo = new PDO('mysql:host=...;dbname=...', '...', '...');
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
// example table
$pdo->exec(
'CREATE TEMPORARY TABLE Foo (
id int auto_increment,
account int,
someotherstuff varchar(32),
primary key(account,id)
) engine=MyIsam'
);
// insert example data
$stmt = $pdo->prepare('INSERT INTO Foo (account,someotherstuff) VALUES (?,?)');
$stmt->execute(array(1, '1a'));
$stmt->execute(array(1, '1b'));
$stmt->execute(array(1, '1c'));
$stmt->execute(array(2, '2a'));
$stmt->execute(array(2, '2b'));
$stmt->execute(array(1, '1d'));
unset($stmt);
// query data
foreach( $pdo->query('SELECT account,id,someotherstuff FROM Foo') as $row ) {
echo $row['account'], ' ', $row['id'], ' ', $row['someotherstuff'], "\n";
}
prints
1 1 1a
1 2 1b
1 3 1c
2 1 2a
2 2 2b
1 4 1d
This should work but is probably slow:
CREATE temporary table seq ( id int, seq int);
INSERT INTO seq ( id, seq )
SELECT id,
(SELECT count(*) + 1 FROM test c
WHERE c.id < test.id AND c.account = test.account) as seq
FROM test;
UPDATE test INNER join seq ON test.id = seq.id SET test.seq = seq.seq;
I have called the table 'test'; obviously that needs to be set correctly. You have to use a temporary table because MySQL will not let you use a subselect from the same table you are updating.

Trying to create a veiw where table 1 data is stored differently

aaiaflat_final
ID Data
1 [2,96,801]
Engine_willie2
ID Data Eng
1 2 3.0
1 96 4.0
1 801 4.6
1 999 5.0
Select
Engine_willie2.ID,
(
CASE
WHEN Engine_willie2.Data = aaiaflat_final.Data
THEN Engine_willie.Data END
)
AS Data,
(
CASE
WHEN Engine_willie2.Data = aaiaflat_final.Data
THEN Engine_willie.Eng END
)
AS Eng
FROM aaiaflat_final
Left Join Engine_willie2 ON
Engine_willie2.ID = aaiaflat_final.ID
WHERE
aaiaflat_final.ID <> ''
I would like the query to look like this
ACES_Query
ID Data Eng
1 2 3.0
1 96 4.0
1 801 4.6
I'm not sure how to parse the [2,96,801] in the aaiaflat_final table as the query works fin if the Data is 2 or any other exact matching data to the data column in Engine_willie2.
Any help would be greatly appreciated.
Joining the tables on id, using replace() to get rid of the brackets and then find_in_set() produces the desired result from the sample data.
SELECT e.id,
e.data,
e.eng
FROM engine_willie2 e
INNER JOIN aaiaflat_final a
ON a.id = e.id
WHERE find_in_set(e.data, replace(replace(a.data, '[', ''), ']', ''));

MySql whole query returns Error 1690 while parts of it doesn't

I know that Error 1690 is nothing new in mysql but after searching for solution here i just gave up. So here I go, the error I get is:
BIGINT UNSIGNED value is out of range in '(v_from#10 - p_from#1)'
The problem is, I do not have any substraction in my query... honestly i even removed "-" from DATE_FORMAT!
My query is:
SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
select count(distinct user_id) as 'event_count_dis',count(user_id) as 'event_count',DATE_FORMAT(event_time,'%Y%m') as 'data',
getEventCourse(event_desc) as 'Name'
from sys_events c where DATE_FORMAT(event_time,'%Y%m') like '201809'
and event_type in ('Clicked')
group by getEventCourse(event_desc)
order by count(distinct user_id) desc Limit 20
Function getEventCourse(event_desc) works perfectly as it is very simple.
When i dissect this query and tested every part of it separately, everything worked fine... and I just gave up... Maybe some of you have any idea what's wrong? or at least can tell me what the heck is
'(v_from#10 - p_from#1)'
Function getEventCourse:
BEGIN
DECLARE courseName varchar(100);
IF(LOCATE('cid',description) > 0) THEN
SET courseName = (Select courses_name from sys_courses where courses_id = test_baza.extract_json_value(description,'cid'));
ELSEIF(LOCATE('course_id',description) > 0) THEN
SET courseName = (Select courses_name from sys_courses where courses_id = test_baza.extract_json_value(description,'course_id'));
ELSE
SET courseName = null;
END IF;
RETURN courseName;
END
sys_events:
event_id | event_time | event_desc | event_type | user_id
1537919 | 2018-10-12 | {"course_id":"386","element_id":"498"}| Clicked | 1235
Edit:
Ok, it seems that problem appears in "group by" section.

How to select static values on mysql select query?

I am new to mysql, here i am trying to get data from database table.
select id,txnid,amount,status from txn_details;
With above query Getting data successfully but status column getting 0 or 1 or 2, but i want 0 as failed, 1 as success and 2 as not processed.
How to change my query?
You can use a case
select id, txnid, amount,
case when status = 0 then 'failed'
when status = 1 then 'success'
else 'not processed'
end as status
from txn_details;
We can use an expression in the SELECT list. It could be a searched CASE expression e.g.
SELECT CASE t.status
WHEN 0 THEN 'failed'
WHEN 1 THEN 'success'
WHEN 2 THEN 'not processed'
ELSE 'unknown'
END AS status_name
, t.status
, t.amount
, t.txnid
FROM txn_details t
This approach is ANSI-92 standards compliant, and will work in most relational databases.
There are some other MySQL specific alternatives, such as the ELT function ...
SELECT ELT(t.status+1,'failed','success','not processed') AS status_name
, t.status
, t.amount
, t.txnid
FROM txn_details t
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_elt
If you prefer a central point of maintenance (ie you prefer not to recode all your queries when a new status comes along) you could create a status table and either use a join or sub query to get the values, alternatively you could create a function, for example
drop table if exists txn_details,txn_status;
create table txn_details(id int, txnid int, amount int , status int);
insert into txn_details values
(1,1,10,1),(2,1,10,2),(3,1,10,4);
create table txn_status (id int, statusval varchar(20));
insert into txn_status values
(1,'success'),(2,'not processed'), (3,'failed');
drop function if exists f;
delimiter $$
create function f(instatus int)
returns varchar(20)
begin
declare rval varchar(20);
return (select
case when instatus = 1 then 'success'
when instatus = 2 then 'not processed'
when instatus = 3 then 'failed'
else 'Unknown'
end
);
select t.*,coalesce(ts.statusval,'Unknown') status
from txn_details t
left join txn_status ts on ts.id = t.status;
select t.*,coalesce((select statusval from txn_status ts where ts.id = t.status),'Unknown') status
from txn_details t;
Note the use of coalesce in case a status is not found.
Both produce this result
+------+-------+--------+--------+---------------+
| id | txnid | amount | status | status |
+------+-------+--------+--------+---------------+
| 1 | 1 | 10 | 1 | success |
| 2 | 1 | 10 | 2 | not processed |
| 3 | 1 | 10 | 4 | Unknown |
+------+-------+--------+--------+---------------+
3 rows in set (0.00 sec)
Using the function like this
select t.*, f(status) as status
from txn_details t;
also produces the same result.
Of course using a status table or a function means you have to communicate their availability and enforce their use.
I would also consider the using a foreign key constraint in txn_details to cut down on the number of unknown values and put procedures in place to stop people adding new status codes at will without going through change control
The following query would work. It uses CASE ... END to determine and return values for the virtual column status.
SELECT id,txnid,amount,
CASE
WHEN status = 0 THEN 'failed'
WHEN status = 1 THEN 'success'
WHEN status= 2 THEN 'not processed'
END AS status
FROM txn_details;

Converting access SQL to MYSQL, How to If(isnull(Max( a column on Insert

beginner here. I'm converting Access sql to MYSQL so I can run bash files and I ran into this 1 issue where 3 days of web searching as lead me no where.
I have a table with two primary fields, "SalesOrderId" and "SOItemID" So the table may look like this:
+--------------+----------+--------+
| SalesOrderid | SOItemId | PartId |
+--------------+----------+--------+
| 10001 | 1 | 147 |
| 10002 | 1 | 152 |
| 10003 | 1 | 152 |
| 10003 | 2 | 188 |
| 10004 | 1 | 105 |
| 10004 | 2 | 84 |
| 10004 | 3 | 209 |
| 10005 | 1 | 5 |
+--------------+----------+--------+
On insert, i need to check if the SalesOrderId exists and if so, +1 the SOItemId field and insert the new record. If not then insert SOItemId as 1. So if I were to insert another PartId to SalesOrderId# 10004, it'd insert as (10004, 4, 299) Here is the code in Access SQL that currently works.
SQL Code:
INSERT INTO SOItem ( SalesOrderId, SOItemId, PartId, CustDeliv, OnDate, Qty, UnitAmount, WebOrderProductId )
SELECT SalesOrder.SalesOrderId, If(IsNull(Max(`SOItemId`,"SOItem","SalesOrderId= " & [SalesOrderId] & " ")),1,DMax("[SOItemId]","SOItem","SalesOrderId= " & [SalesOrderId] & " ")+1) AS Expr1, ICS_Web_Parts_Link.PartId, SalesOrder.Date, SalesOrder.Date, order_product.quantity, order_product.price, order_product.order_product_id
FROM (order_product INNER JOIN ICS_Web_Parts_Link ON order_product.model = ICS_Web_Parts_Link.Model) INNER JOIN SalesOrder ON order_product.order_id = SalesOrder.WebOrderId;
Here's my MYSQL version:
INSERT INTO `SOItem` ( SalesOrderId, SOItemId, PartId, CustDeliv, OnDate, Qty, UnitAmount, WebOrderProductId )
SELECT `SalesOrder`.`SalesOrderId`, If(IsNull(Max(`SOItem`.`SOItemId`, `SOItemId`.`SalesOrderId` = `SalesOrder`.`SalesOrderId`)),1,Max(`SOItem`.`SOItemId`, `SOItemId`.`SalesOrderId` = SalesOrder`.`SalesOrderId`)+1) AS Expr1, ICS_Web_Parts_Link.PartId, SalesOrder.Date, SalesOrder.Date, order_product.quantity, order_product.price, order_product.order_product_id
FROM (order_product INNER JOIN ICS_Web_Parts_Link ON order_product.model = ICS_Web_Parts_Link.Model) INNER JOIN SalesOrder ON order_product.order_id = SalesOrder.WebOrderId;
I get this error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' SOItemId.SalesOrderId = SalesOrder.SalesOrderId)),1,Max(SOItem.`SOIte' at line 2
Any help would be greatly appreciated. -Dan
The syntax SOItemId.SalesOrderId implies that you're referencing a table called SOItemId, which has a column called SalesOrderId. That's clearly not what you're doing (there's no table with that name, at least not joined to this query), so that's why it's throwing a syntax error at you.
It's not clear exactly what you are trying to join to what. I suggest you spend some more time looking at SQL exercises and examples of working code. While you're at it, make sure you understand how MAX and ISNULL work in MySQL. (Consider using IFNULL or COALESCE instead.)
Here's how to do this in MySQL. This is just an example using what you referenced above but you can execute it as-is to see how it works and then apply it to your use-case.
DROP TABLE IF EXISTS sales_test;
CREATE TABLE `sales_test` (
`SalesOrderid` int(11) DEFAULT NULL,
`SOItemId` int(11) DEFAULT NULL,
`PartId` int(11) DEFAULT NULL,
PRIMARY KEY (SalesOrderid, SOItemId),
UNIQUE KEY `SalesOrderid` (`SalesOrderid`,`SOItemId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO sales_test (SalesOrderid, SOItemId, PartId) VALUES
(10001, 1, 147),
(10002, 1, 152),
(10003, 1, 152),
(10003, 2, 188),
(10004, 1, 105),
(10004, 2, 84),
(10004, 3, 209),
(10005, 1, 5);
SELECT * FROM sales_test;
INSERT INTO sales_test (SalesOrderid, SOItemId, PartId)
VALUES (10005, 1, 5)
ON DUPLICATE KEY UPDATE SOItemId = SOItemId + 1;
SELECT * FROM sales_test;
I was finally able to figure it out. Thanks for all your help!
To anybody with the same problem, here is the mysql code that works.
INSERT INTO `SOItem` ( SalesOrderId, SOItemId, PartId, CustDeliv, OnDate, Qty, UnitAmount, WebOrderProductId )
SELECT `SalesOrder`.`SalesOrderId`, IF((SELECT (SOItem.SOItemId) FROM d1.SOItem WHERE SalesOrder.SalesOrderId = SOItem.SalesOrderId) IS NULL, 1, (SELECT MAX(SOItem.SOItemId)+1 FROM d1.SOItem WHERE SalesOrder.SalesOrderId = SOItem.SalesOrderId)) AS Expr1, ICS_Web_Parts_Link.PartId, SalesOrder.Date, SalesOrder.Date, order_product.quantity, order_product.price, order_product.order_product_id
FROM d2.order_product INNER JOIN d1.ICS_Web_Parts_Link ON order_product.model = ICS_Web_Parts_Link.Model INNER JOIN d1.SalesOrder ON order_product.order_id = SalesOrder.WebOrderId LEFT JOIN d1.SOItem ON order_product.order_product_id = SOItem.WebOrderProductId
WHERE NOT EXISTS (SELECT order_product_id FROM d2.order_product WHERE order_product.order_product_id = SOItem.WebOrderProductId);