GROUP_CONCAT as input of MySQL function - mysql

Is it possible to use a GROUP_CONCAT in a SELECT as the input of a MySQL function? I cannot figure out how to cast the variable it seems. I've tried blob. I've tried text (then using another function to break it up into a result set, here) but I haven't had any success.
I want to use it like this:
SELECT
newCustomerCount(GROUP_CONCAT(DISTINCT items.invoicenumber)) AS new_customers
FROM items;
Here is the function:
DROP FUNCTION IF EXISTS newCustomerCount;
DELIMITER $$
CREATE FUNCTION newCustomerCount(invoicenumbers BLOB)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE new_customers INT;
SET new_customers = 0;
SELECT
SUM(nc.record) INTO new_customers
FROM (
SELECT
1 AS customer,
(SELECT COUNT(*) FROM person_to_invoice ps2 WHERE person_id = ps1.person_id AND invoice < ps1.invoice) AS previous_invoices
FROM person_to_invoice ps1
WHERE invoice IN(invoicenumbers)
HAVING previous_invoices = 0
) nc;
RETURN new_customers;
END$$
DELIMITER ;

Because Mysql functions do not support dynamic queries, I recommend you re-think your basic strategy to pass in a list of invoice numbers to your function. Instead, you could modify your function to accept a single invoice number and return the number of new customers just for the one invoice number.
Also, there are some optimizations you can make in your query for finding the number of new customers.
DROP FUNCTION IF EXISTS newCustomerCount;
DELIMITER $$
CREATE FUNCTION newCustomerCount(p_invoice INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE new_customers INT;
SET new_customers = 0;
SELECT
COUNT(DISTINCT ps1.person_id) INTO new_customers
FROM
person_to_invoice ps1
WHERE
ps1.invoice = p_invoice
AND NOT EXISTS (
SELECT 1
FROM person_to_invoice ps2
WHERE ps1.person_id = ps2.person_id
AND ps2.invoice < ps1.invoice
);
RETURN new_customers;
END$$
DELIMITER ;
Then you can still get the total number of new customers for a given list of invoice numbers like this:
SELECT
SUM(newCustomerCount(invoice)) as total_new_customers
FROM items
WHERE ...

You could try FIND_IN_SET() instead of IN(). The performance will probably be horrible when passing in a long list of invoice numbers. But it should work.
WHERE FIND_IN_SET(invoice, invoicenumbers)

You are looking in the wrong place.
WHERE invoice IN(invoicenumbers) will not do the desired substitution. Instead you need to use CONCAT to construct the SQL, then prepare and execute it.

Related

Invalid use of group function when using count() MySQL

I'm trying to get the average amount of orders per customer and I've tried a bunch of things but I can't find an answer that works to this particular problem.
With pretty much everything I've tried I get Error 1111: Invalid use of group function.
Results on google are only talking about not using where statements so I'm a little lost.
DELIMITER //
create function avgAmount()
returns double
BEGIN
DECLARE AvgAmountOfOrders double;
SET AvgAmountOfOrders = (COUNT(DISTINCT orderID) * 1.0) / NULLIF(COUNT(DISTINCT CustomerID), 0) ;
return AvgAmountOfOrders;
END;//
DELIMITER ;
Select avgAmount();
Thank you The Impaler.
For anyone interested this was the solution.
DELIMITER //
create function test123()
returns double
BEGIN
DECLARE AvgAmountOfOrders double;
SET AvgAmountOfOrders = (select COUNT(DISTINCT OrderID * 1.0) / NULLIF(COUNT(DISTINCT CustomerID), 0)from orders) ;
return AvgAmountOfOrders;
END;//
DELIMITER ;
Select test123();

"Delimiter" is not valid at this position, expecting CREATE

I was getting an error of "Delimiter" is not valid at this position, expecting CREATE" as I was writing a stored procedure and couldn't figure out the cause. I think it might be an issue with MySQL workbench possibly, because the following code gives the same error but was copied straight off of this website.
DELIMITER $$
CREATE PROCEDURE GetTotalOrder()
BEGIN
DECLARE totalOrder INT DEFAULT 0;
SELECT COUNT(*)
INTO totalOrder
FROM orders;
SELECT totalOrder;
END$$
DELIMITER ;
Edit: My real stored procedure is:
DELIMITER //
CREATE PROCEDURE GetSimilar(inputdate char(10))
BEGIN
Declare id(tinyint) DEFAULT 0;
Set id := (select t.IdTimelineinfo
From timelineinfo t
WHERE t.Date = inputdate);
SELECT t.Date From timelineinfo t where t.date = inputdate;
SELECT o.Name, o.Race, o.Sex, o.IdOfficer
FROM timelineinfo
JOIN timelineinfo_officer ON timelineinfo.IdTimelineinfo = timelineinfo_officer.IdTimelineinfo
JOIN officers o ON timelineinfo_officer.IdOfficer = o.IdOfficer
WHERE timelineinfo.IdTimelineinfo = id
UNION
SELECT s.IdSubject, s.Name, s.Race, s.Sex
FROM timelineinfo
JOIN timelineinfo_subject ON timelineinfo.IdTimelineinfo = timelineinfo_subject.IdTimelineinfo
JOIN subjects s ON timelineinfo_subject.IdSubject = s.IdSubject
WHERE timelineinfo.IdTimelineinfo = id;
UNION
Select *
From media m
Where (m.IdTimelineinfo = id);
END //
DELIMITER ;
Watch out where you edit the procedure SQL code. There's a dedicated routine object editor (just like there are for tables, triggers, views etc.), which only accept SQL code for their associated object type. Hence they don't need a delimiter and even signal an error if you use one.
On the other hand you can always directly edit SQL code in the SQL IDE code editors, where no such special handling is implemented. In this case you need the delimiter.

Use MySQL query result in a loop

I just started working with SQL and have been working with MySQL.I am trying to write a stored procedure that will take each value from my buyPrice column in my products table, and store each value into a variable. I then want it to multiply this variable by the sales tax and then take each result and place it into my empty sales_tax column. I would like to populate the whole column with the sales tax for each item. When I execute this method I get some error saying the productCode doesn't have a default value. What is the proper way to write this? I know this isn't the most efficient way of doing this task, just trying to practice.
DELIMITER //
CREATE PROCEDURE nFirstProcedure()
BEGIN
DECLARE IdValue, counter, holdValue, result INT DEFAULT 0;
DECLARE holdName VARCHAR(30);
SET counter = 1;
WHILE counter < ( SELECT COUNT(*) FROM products)
DO
SET holdValue = (SELECT buyPrice FROM products WHERE sales_tax = null);
SET result = (holdValue * 0.08);
INSERT INTO products (sales_tax) VALUES (result);
END WHILE;
END//
DELIMITER ;
You should not do this with a loop. Just use update:
update products
set sales_tax = buyPrice * 0.08
where sales_tax is null;

Trying to get Count single value from mysql stored procedure

I am trying to do a count in a mysql stored procedure but cant get the syntax right help1
delimiter//
create procedure get_count_workmen_type(
IN employee_payroll int,
OUT mycount int
)
begin
SELECT count(*) into mycount from workman
where employee_payroll = employee_payroll
end //
delimiter;
You should prefix your parameter names (personally I use "p_") to differentiate them from column names, etc. For example where employee_payroll = employee_payroll will always be true because it's comparing the column to itself.
Also you should add a semi-colon to the end of your select statement.
Putting those two changes together gives you something like this:
delimiter //
create procedure get_count_workmen_type(
IN p_employee_payroll int,
OUT p_mycount int
)
begin
SELECT count(*)
into p_mycount
from workman
where employee_payroll = p_employee_payroll;
end //
delimiter ;

How to set a variable as query result in a MySQL stored procudure?

A rather simple question, but I can only find answers to more complex questions.
I'm working on a stored procudure and am currently inside a REPEAT loop. I need to run the following query in the loop to get the 1 column value that is returned (only 1 record will be returned). This will need to be stored as a var to be used later in the loop.
SELECT photo_id FROM photos ORDER BY photo_id DESC LIMIT 1;
How do I set that to 'last_photo_id' to be used later in the stored procdure?
You could do something like this:
SELECT #varname := photo_id
FROM photos
ORDER BY photo_id DESC
LIMIT 1;
That is, if you are sure there's no other way to do what you want to do than in a loop. For SQL works best when you use it for set-based solutions.
Try this:
DECLARE total_products INT DEFAULT 0
SELECT COUNT INTO total_products
FROM products
You can use a function
So for example
SET i_camera_count = get_camera_count(i_photo_camera_data_id);
and then make a function like this.
DELIMITER $$
DROP FUNCTION IF EXISTS `get_camera_count` $$
CREATE DEFINER=`root`#`localhost` FUNCTION `get_camera_count`(camera_id_2 INT(10)) RETURNS int(11)
BEGIN
DECLARE v_return_val INT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_return_val = -1;
SELECT x FROM y WHERE camera_id = camera_id_2
RETURN v_return_val;
END $$
DELIMITER ;