List all 'feeds' and only 2 users with relationship - mysql

I need to make a list of all the items in the table feed and show only the first 2 users who subscribe to the content, but I can not put together a query that does the list only 2 users limit 2.
I've tried N querys and subquery, but could not get the expected result. The nearest was using group_concat, but if it concatenates all users and does not allow limited only to two initial, and would have to usesubstring_index for this purpose.
Query
select
feed.id
, feed.type
, user.name
from feed
inner join user on user.id = feed.user
group by feed.type
Result
Array(
[0] => Array(
[id] => 1
[type] => Comedy
[name] => Mike
)
[1] => Array(
[id] => 3
[type] => War
[name] => John
)
[2] => Array(
[id] => 6
[type] => Terror
[name] => Sophia
)
)
Expected
Array(
[0] => Array(
[id] => 1
[type] => Comedy
[name] => Mike, Papa
)
[1] => Array(
[id] => 3
[type] => War
[name] => John, Alex
)
[2] => Array(
[id] => 6
[type] => Terror
[name] => Sophia, Jessica
)
)

set #rn=0;
select id, type, name
from
(
select
#rn:=#rn+1 AS r_n
,feed.id
,feed.type
,user.name
from feed
inner join user on user.id = feed.user
group by feed.id
order by feed.id) t
where t.r_n <= 2
You can generate row numbers per group and then select the first 2 rows per feed id.

I don't know exactly the schema of your tables but try the same approach you already tried with group_concat but join to a subquery like:
...
inner join
(
select user.id, user.name from user limit 2
) as x on x.id = feed.user
...

You can use variables to simulate row_number() to give each user per feed a "rank" and only select rows with number <= 2 before doing the grouping in order to only get 2 users per group:
select id, type, group_concat(name) from (
select * from (
select *, #rn := if(#prevFeedId = id, #rn+1, 1) as rn,
#prevFeedId := id
from (
select
feed.id
, feed.type
, user.name
from feed
inner join user on user.id = feed.user
) t1 order by id
) t1 where rn <= 2
) t1 group by id, type

Related

mysql - total sum of all grouped count(*) 's with order by and limit (fiddle included)

Having trouble figuring this one out... I know what is wrong with the below, but not sure how to go about getting the results I want. Having two separate queries is not possible without a lot of extra refactoring which I want to avoid by doing this is one query... even though the TotalSum is duplicated for each result in the set.
SELECT
data_logs.event_target AS Name,
COUNT(*) AS Total,
SUM(COUNT(*)) OVER() AS TotalSum
FROM data_logs
GROUP BY Name
ORDER BY Total DESC
LIMIT 10
What I want is TotalSum to be the total of all the grouped COUNT(*)'s (10 in this case). The problem is "windowing execution occurs before ORDER BY, LIMIT, and SELECT DISTINCT" so the total ends up being wrong... it is the total of ALL rows instead of the 'top 10' with my limit.
Array
(
[0] => Array
(
[Name] => somename0
[Total] => 11
[TotalSum] => 61
)
[1] => Array
(
[Name] => somename1
[Total] => 4
[TotalSum] => 61
)
[2] => Array
(
[Name] => somename2
[Total] => 3
[TotalSum] => 61
)
[3] => Array
(
[Name] => somename3
[Total] => 2
[TotalSum] => 61
)
[4] => Array
(
[Name] => somename4
[Total] => 2
[TotalSum] => 61
)
[5] => Array
(
[Name] => somename5
[Total] => 2
[TotalSum] => 61
)
[6] => Array
(
[Name] => somename6
[Total] => 2
[TotalSum] => 61
)
[7] => Array
(
[Name] => somename7
[Total] => 1
[TotalSum] => 61
)
[8] => Array
(
[Name] => somename8
[Total] => 1
[TotalSum] => 61
)
[9] => Array
(
[Name] => somename9
[Total] => 1
[TotalSum] => 61
)
)
In the above [TotalSum] should be 29 for all of them... the total of all 10 [Total] values.
FIDDLE : https://www.db-fiddle.com/f/agn932Q9eXxhcm3CE26THe/2
You can aggregate and limit first in a subquery, then compute the grand total:
SELECT t.*, SUM(total) OVER() AS TotalSum
FROM (
SELECT event_target AS Name, COUNT(*) AS Total
FROM data_logs
GROUP BY Name
ORDER BY Total DESC
LIMIT 10
) t

MYSQL group concat selecting multiple rows

Query:
SELECT `category`.*,
Group_concat(DISTINCT `sub_category`.`english_name` ORDER BY
`sub_category`.`order_number`
ASC) AS `sub_category`,
Group_concat(DISTINCT `sub_category`.`id` ORDER BY
`sub_category`.`order_number`
ASC) AS `sub_category_id`,
Group_concat(`sub_category`.`status` ORDER BY
`sub_category`.`order_number` ASC)
AS `sub_category_status`
FROM `category`
LEFT JOIN `item_category`
ON `item_category`.`category` = `category`.`id`
LEFT JOIN `sub_category`
ON `sub_category`.`category` = `category`.`id`
GROUP BY `category`.`id`
ORDER BY `category`.`order_number` ASC
Problematic line:
Group_concat(sub_category.status ORDER BY
sub_category.order_number ASC)
Result:
(
[ID] => 22
[Create_date] => 2017-11-20
[Created_by] => 0
[English_name] => Pens & refills
[Gujarati_name] => પેન અનેર રીફીલ
[Header] => False
[Sidebar] => False
[Order_number] => 2
[Status] => Close
[sub_category] => Botteled Ink,Fountain Pens,gel ink rollball pens
[sub_category_id] => 54,55,56
[sub_category_status] => Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open,Open
)
As you can see I used DISTINCT where I can use. Status either open or close so DISTINCT is not helpful in this column. Can anyone please tell me How can I solve this issue?
You missed DISTINCT For sub_category_status Thats why you are getting duplicate value
Group_concat(`sub_category`.`status` ORDER BY
`sub_category`.`order_number` ASC)
AS `sub_category_status`
ADD DISTINCT for above column also
Group_concat( DISTINCT `sub_category`.`status` ORDER BY
`sub_category`.`order_number` ASC)
AS `sub_category_status`

How to insert a max value plus one in mysql in opencart

I have the following:
Model File
$max = $this->db->query("SELECT MAX( sort ) FROM lc_menu");
print_r($max);
Printed Values
stdClass Object ( [num_rows] => 1 [row] => Array ( [MAX( sort )] => 64 )
[rows] => Array ( [0] => Array ( [MAX( sort )] => 64 ) ) )
How can I insert max+1 in MySQL query?
You can use subquery:
$this->db->query('INSERT INTO ' . DB_PREFIX . ' menu SET
menuname = "$this->db->escape($data['menuname'])",
start_date = "$this->db->escape($data['start_date'])",
start_time = "$this->db->escape($data['start_time'])",
end_date = "$this->db->escape($data['end_date'])",
end_time = "$this->db->escape($data['end_time'])",
link_value = "$this->db->escape($data['link_value'])",
link = "$this->db->escape($alpha['link'])",
sort = ((SELECT MAX(sort) FROM lc_menu) + 1)');

Fetching 10 items each of child table in mysql

I have a table categories (id, cat_name) and a table recipes (id, cat_id, recipe_text).
Now I want to write a query, that fetches from each category 10 recipes.
SELECT cat_name, recipe_text
FROM categories c
JOIN recipes r ON c.id=r.cat_id
would fetch ALL recipes, but I want a maximum of 10 recipes per category.
(How) could it be done with a SQL-Query?
Taken from mySQL Returning the top 5 of each category:
SELECT cat_name, recipe_text
FROM
(
SELECT c.cat_name AS cat_name, r.recipe_text AS recipe_text,
#r:=case when #g=c.id then #r+1 else 1 end r,
#g:=c.id
FROM (select #g:=null,#r:=0) n
CROSS JOIN categories c
JOIN recipes r ON c.id = r.cat_id
) X
WHERE r <= 10
You may try the below code
function recipe($cat_id='',$new_ar=array())
{
if($cat_id!="")
{
$new_ar1=array();
$db="select recipe_text from recipes where cat_id=".$cat_id." order by cat_id limit 10";
$sq=mysql_query($db);
while($fe=mysql_fetch_object($sq))
{
array_push($new_ar1,$fe->recipe_text);
}
return $new_ar1;
}
else
{
$db="select id,cat_name from categories order by id";
$sq=mysql_query($db);
while($fe=mysql_fetch_object($sq))
{
array_push($new_ar,$fe->cat_name);
$new_ar[$fe->id]=array($fe->cat_name);
array_push($new_ar[$fe->id],recipe($fe->id,$new_ar));
}
}
}
recipe();
it will give output like below
Array
(
[0] => cat 1
[1] => Array
(
[0] => cat 1
[1] => Array
(
[0] => rice
[1] => curry
[2] => mutton
[3] => A recipe
[4] => B recipe
[5] => C recipe
[6] => D recipe
[7] => E recipe
[8] => F recipe
[9] => G recipe
)
)
[2] => Array
(
[0] => cat 2
[1] => Array
(
[0] => dal
[1] => fish
)
)
[3] => Array
(
[0] => cat 3
[1] => Array
(
)
)
[4] => Array
(
[0] => cat 4
[1] => Array
(
)
)
)
Thanks
Ripa Saha
this will do for u...
SET #rank = 0;
SELECT cat_name,recipe_text FROM (SELECT
id,cat_id AS P,recipe_text,
CASE
WHEN #rowdata != pid
THEN #rank := 0 & #rowdata := cat_id
ELSE #rank := #rank + 1
END AS rank
FROM
recipes
GROUP BY cat_id,
id
) X ,t
WHERE X.rank <= 3 AND X.p = t.cat_id;
Try below SQL
select
cat_name,
recipe_text
from categories as c,recipes as r
where c.id=r.cat_id limit 10
We finally made a stored procedure:
DELIMITER $$
CREATE PROCEDURE `test`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cur_id INT;
DECLARE cur CURSOR FOR
SELECT id FROM category;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
CREATE TABLE tmp(catname VARCHAR(255), recipeId INT);
OPEN cur;
the_loop: LOOP
FETCH cur INTO cur_id;
IF done THEN
LEAVE the_loop;
END IF;
INSERT INTO tmp(catname, recipeId)
SELECT catname, recipeId
FROM category c LEFT JOIN recipes r ON c.id=r.cat_Id
WHERE c.id=cur_id
LIMIT 0, 10;
END LOOP;
SELECT * FROM tmp;
DROP TABLE tmp;
END
SET #num :=0, #cat_id := '';
SELECT recipe_text,cat_name,
#num := if(#cat_id = cat_id, #num + 1, 1) as row_number,
#cat_id := cat_id as cat_id
FROM recipes r
JOIN categories c ON c.id = r.cat_id
group by cat_name,recipe_text
having row_number <= 10

MYSQL, DATETIME, Events, Group by Month/Year in SQL or at output?

I have an events table with a start_date field, a standard date time. I am looking to select all the events in the table, and then output them in groups, separated by the events respective Month and year.
I am using this query:
SELECT Event.id, Event.name, Event.start_date, Event.end_date,
EXTRACT(MONTH FROM `Event`.`start_date`) AS `event_month`,
EXTRACT(YEAR FROM `Event`.`start_date`) AS `event_year`
FROM `my_events` AS `Event`
which produces the following $events array: (using CakePHP)
Array
(
[0] => Array
(
[Event] => Array
(
[id] => 1
[name] => Event Name One
[start_date] => 2011-07-03 11:00:00
[end_date] => 2011-07-03 16:00:00
)
[0] => Array
(
[event_month] => 7 // This event occurs in July
[event_year] => 2011
)
)
[1] => Array
(
[Event] => Array
(
[id] => 2
[name] => Event Name Two
[start_date] => 2011-07-09 11:00:00
[end_date] => 2011-07-09 15:00:00
)
[0] => Array
(
[event_month] => 7 // this event occurs in July
[event_year] => 2011
)
)
[2] => Array
(
[Event] => Array
(
[id] => 3
[name] => Event Name Three
[start_date] => 2011-07-09 11:00:00
[end_date] => 2011-07-09 15:00:00
)
[0] => Array
(
[event_month] => 8 // this event occurs in august.
[event_year] => 2011
)
)
I am looking to now cycle through these arrays, and produce output such as:
July
Event Name One
Event Name Two
August
Event Name Three
I have opted to use the EXTRACT SQL function as it appeared to be quite a common method of grabbing data for such a purpose.
I considered that array_merge might be an option, but $result = array_merge($event) doesn't appear to do anything.
Am I on the right lines, or would there be a better way to achieve this?
Thanks.
use group by:
select month( event.start_date), year( event.start_date), group_concat( distinct event.name ) from my_events event group by year(event.start_date), month(event.start_date);
You can use the YEAR() and MONTH() or the MONTHNAME() functions but I don't think you need GROUP BY but ORDER BY:
SELECT YEAR( Event.start_date ) AS event_year
, MONTH( Event.start_date ) AS event_month
, MONTHNAME( Event.start_date ) AS event_month_name
, Event.id
, Event.name
, Event.start_date,
, Event.end_date
FROM my_events AS Event
WHERE Event.start_date >= '2011-07-01'
AND Event.start_date < '2013-01-01'
ORDER BY Event.start_date ASC
And you use the event_year and event_month in your PHP code to add the July, August, etc... and 2011 tags when the month or year changes from one row to the next.