I'm new in sql, so i need your help! I need a stored procedure to get a certain number of articles with some offset and total number of them to make pagination...
is this a correct code or there is a better way? How much queries will be executed, 1 for ctid, 1 for total and 1 for content data??
DELIMITER $$
CREATE PROCEDURE `getArticles`(`offset` INT, `count` INT)
BEGIN
DECLARE ctid, total INT;
SET ctid = (SELECT id FROM content_types WHERE name='article');
SET total = (SELECT COUNT(*) FROM content WHERE content_type = ctid);
SELECT *, total FROM content
WHERE content_type = ctid
LIMIT count
OFFSET offset;
END $$
DELIMITER ;
You can try to leverage SQL_CALC_FOUND_ROWS option and FOUND_ROWS() function
SQL_CALC_FOUND_ROWS and FOUND_ROWS() can be useful in situations when
you want to restrict the number of rows that a query returns, but also
determine the number of rows in the full result set without running
the query again. An example is a Web script that presents a paged
display containing links to the pages that show other sections of a
search result. Using FOUND_ROWS() enables you to determine how many
other pages are needed for the rest of the result.
That being said your procedure might look like
DELIMITER $$
CREATE PROCEDURE get_articles(IN _offset INT, IN _count INT, OUT _total INT)
BEGIN
SELECT SQL_CALC_FOUND_ROWS *
FROM content c JOIN content_types t
ON c.content_type = t.id
WHERE t.name = 'article'
LIMIT _offset, _count;
SET _total = FOUND_ROWS();
END$$
DELIMITER ;
Sample usage:
SET #total = 0;
CALL get_articles(0, 3, #total);
SELECT #total;
Here is SQLFiddle demo
I guess your lookin a query like this. Try to do everything in the same query, if it doesn't get too complex.
SELECT c.*,
(SELECT COUNT(*) FROM content AS c1 WHERE c1.content_type = ct.id) AS total
FROM content AS c
INNER JOIN content_type AS ct ON c.content_type = ct.id
WHERE ct.name = 'article'
LIMIT offset, count;
Related
I have 100 rows in table tbl_master_sales and an empty table tbl_customer_sales.When I use WHILE loop to insert data from tbl_master_salesto tbl_customer_sales,it only inserts 50 rows.However,it should have insert 100 rows taking two iteration of while loop.What may be my mistake in following PROCEDURE:
CREATE PROCEDURE ROWPERROW()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM tbl_master_sales INTO n;
SET i=0;
WHILE i<n DO
INSERT INTO tbl_customer_sales (id,card_number,customer_name,customer_phone,bill_no,item_code,division,section,department,item_name,store,promo_name,billdiscount_name,billqty,promo_amount,bill_discount_amount,loyaltyamount,net_amount)
SELECT id, card_number, customer_name, customer_mobile, billno, itemcode, division, section, department, itemname, store, promoname, billdiscountname, billqty, promoamount, billdiscountamount, loyaltyamount, netamount
FROM tbl_master_sales
WHERE NOT EXISTS(SELECT 1
FROM tbl_customer_sales
WHERE id=tbl_master_sales.id)
LIMIT i,50;
SET i = i + 50;
END WHILE;
End;;
I don't see anything wrong with your procedure code logic but the reason for inserting only 50 rows could be the NOT EXISTS part shown below, which is restricting from inserting duplicate rows (or) filtering out the rest records.
WHERE NOT EXISTS(
SELECT 1
FROM tbl_customer_sales
WHERE id=tbl_master_sales.id)
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.
I have a MYSQL table and two of the fields are called Rate_per_unit and Cost. First I want the field Rate_per_unit to populate itself from another table called SHD_TEACHER then I want the field COST to populate itself also from RATE in SHD_TEACHER and multiplies by UNITS.
I have the following code which is giving me an error:
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT RATE
FROM SHD_TEACHER
WHERE TEACHERID = NEW.TEACHER_ID
) * UNITS
Any help please?
thanks
using your syntax, I would expect a delimiter statement and a begin/end block. So, try this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SET NEW.RATE_PER_UNIT =
(
SELECT RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
)
SET NEW.COST = (
SELECT t.RATE
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
) * NEW.UNITS
END $$
DELIMITER ;
You have a limit 1 in the first subquery, suggesting that there might be multiple matches. If so, you will get a run-time error in the second. Also, UNITS is just hanging out there, all alone. I assumed it is in the NEW record.
Here is another way to write this:
DELIMITER $$
CREATE TRIGGER RATE_PER_UNIT_1
BEFORE INSERT ON SHD_SCHEDULE
FOR EACH ROW
BEGIN
SELECT NEW.RATE_PER_UNIT := t.RATE, NEW.COST := t.RATE * NEW.UNITS
FROM (SELECT t.*
FROM SHD_TEACHER t
WHERE t.TEACHERID = NEW.TEACHER_ID
LIMIT 1
) t
END $$
DELIMITER ;
I have a table fanclubs (f_count_m /*count of members*/, id_band /*id of the music band*/) and I need a function that returns back the id_band of the most popular band.
Code:
delimiter //
create function best_of (b varchar(2))
returns varchar(6)
begin
DECLARE b varchar(6);
SET #b =
(select s_and_id.id_band from
(select sum(f_count_m), id_band
from fanclubs
group by id_band
order by f_count_m desc
LIMIT 0,1) as s_and_id);
return b;
end//
delimiter ;
The select part returns one id. But if I try to use a created function like this:
select #best_of
or
select * from fanclubs where id_band = #best_of
I get NULL.
The same with #b
Where am I wrong?
How about
SELECT id_band FROM fanclubs ORDER BY f_count_m DESC LIMIT 1;
I haven't tested this (I'm on my tablet), but I think the logic is sound.
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 ;