I have tables as described below:
subscription_plans (Table for storing all plans)
id plan days_limit added_on status rate
------------------------------------------------
1 PlanA 15 1398249706 1 150.00
2 PlanB 15 1398249706 1 150.00
subscribed_videos (Table for storing details of video in each plans)
id plan_id videoid
----------------------
1 1 1
2 2 2
subscription_groups (Table for storing groups where a plan can be part of another plan. ie, Plan A be a plan with 2 other individual plans, Plan B and C )
id plan_id assosiated_plan_id added_on
----------------------------------------------
1 1 2 1398249706
usersubscription (Table for storing user subscribed plans)
id user_id plan_id subscribed_on
---------------------------------------
1 1 1 1398771106
Now, my problem is that how can I get the count of videos for each plans. If Plan A contains both Plan B and C (subscription_groups table), then the count should return the total video count for each individual plans in that particular plan. Now I have done with a query which will return plan details along with count of videos for a plan but I am not able to join it with subscription_groups. How can I accomplish this in a single query.
$data['planquery']=$this->db->query("select
us.plan_id,us.subscribed_on,sp.plan,sp.days_limit,sp.rate,count(sv.videoid) from
usersubscription as us INNER JOIN
subscription_plans as sp ON us.plan_id=sp.id INNER JOIN subscribed_videos as sv ON sp.id=sv.plan_id where sp.status=1 and us.user_id=1");
Expected Result:
plan_id subscribed_on plan days_limit rate count
-------------------------------------------------------
1 1398771106 PlanA 15 150.00 2
Can anyone help me to find a solution for this?
Thanks in advance.
You can do so
SELECT
us.plan_id,
us.subscribed_on,
sp.plan,
sp.days_limit,
sp.rate,
COUNT(sv.videoid)
FROM
usersubscription AS us
RIGHT JOIN subscription_plans AS sp
ON us.plan_id = sp.id
INNER JOIN subscribed_videos AS sv
ON sp.id = sv.plan_id
INNER JOIN subscription_groups g
ON(g.plan_id =sv .plan_id OR sv.plan_id= g.assosiated_plan_id)
WHERE sp.status = 1
AND (us.user_id = 1 OR us.user_id IS NULL )
Demo
Since user has only plan associated but the associated plan can also has another plan linked so the last condition will check the user id but for is null to for the second linked plan user id will be null due to right join on subscription_plans
Edit
SELECT
u.plan_id,
u.subscribed_on,
p.plan,
p.days_limit,
p.rate
,COUNT(DISTINCT v.`videoid`)
FROM `usersubscription` u
JOIN `subscription_groups` g
ON (u.`plan_id` = g.`plan_id`)
RIGHT JOIN `subscription_plans` p
ON(u.`plan_id` = p.`id` OR g.`assosiated_plan_id` = p.`id`)
INNER JOIN `subscribed_videos` v ON(v.`plan_id`=g.`assosiated_plan_id` OR u.`plan_id`= v.`plan_id`)
WHERE u.`id`=1 AND p.`status` = 1
Demo 1 Demo2
For video ids you can use group_concat
SELECT
u.plan_id,
u.subscribed_on,
p.plan,
p.days_limit,
p.rate
,COUNT(DISTINCT v.`videoid`) `video_count` ,
GROUP_CONCAT(DISTINCT v.`videoid`) `video_ids`
FROM `usersubscription` u
JOIN `subscription_groups` g
ON (u.`plan_id` = g.`plan_id`)
RIGHT JOIN `subscription_plans` p
ON(u.`plan_id` = p.`id` OR g.`assosiated_plan_id` = p.`id`)
INNER JOIN `subscribed_videos` v ON(v.`plan_id`=g.`assosiated_plan_id` OR u.`plan_id`= v.`plan_id`)
WHERE u.`id`=1 AND p.`status` = 1
Demo 1a Demo 2a
Related
Table 1
----------
NameID Name
------------------
1 A
2 B
3 C
-----------------
Table 2
--------------------
ID NameID Order
--------------------
1 1 Sugar
2 1 Salt
3 2 Garlic
4 2 Sugar
5 2 Onion
6 3 Oil
7 3 Black pepper
I want to return only the latest and only one record per nameID from
right table I dont know what code to use
This is the Result I want to return
RESULT
----------------------------
Name Order
---------------------------
A Salt
B Onion
C Black pepper
Controller.php
return DB::table('table1')
->leftjoin('table2','table1.nameID','=','table2.nameID')
-get();
try this
$data = Table1::select('Table1.Name', 'Table2.Order','Table2.ID')
->leftJoin('Table2', function($query) {
$query->on('Table1.NameID','=','Table2.NameID')
->whereRaw('Table2.ID IN (select MAX(a2.ID) from Table2 as a2 join Table1 as u2 on u2.NameID = a2.NameID group by u2.NameID)');
})->get();
Edited :
$data = Table1::select('Table1.Name', 'Table2.Order','Table2.ID')
Use not exists to filter
select Name, Order
from Table1 a
inner join
(
Select a.NameID, Order from Table2 a
where not exists(select 1 from Table2 b where a.NameID = b.NameID and a.ID < b.ID)
)b on a.NameID = b.NameID
You can try this below script-
SELECT B.NameID, B.Name, C.[Order]
FROM
(
SELECT Nameid,MAX(ID) ID
FROM table_2
GROUP BY NameID
)A
INNER JOIN Table_1 B ON A.NameID = B.NameID
INNER JOIN Table_2 C ON A.NameID = C.NameID AND A.ID = C.ID
I have multiple tables I am trying to grab data from in a single query. I seem to be close to a solution but can not seem to get the data result I am expecting.
Examples of my tables are as follows (fields have been truncated):
Table c
id
name
abbreviation
Table mr (relationship table tat ties tables c and m together by ID)
id
c.id
m.id
Table m
id
Table cnt
id
c.id
Table cmp
id
cnt.id
active
What I WANT is all fields from C, all fields from M where m.id = c.id, all active (active = 1) id's from CMP that match on cnt.id.
My most recent query (after dozens of iterations) is:
SELECT c.id AS id
, c.name AS name
, c.abbreviation AS abbr
, c.active AS active
, c.last_modified AS last_modified
, c.modified_by AS modified_by
, mr.media_id
, mr.related_object_table
, mr.related_object_id
, m.orig_name AS img_name
, m.unique_name AS img_slug
, m.file_type AS confed_file_type
, m.file_size AS file_size
, COUNT('cmp.id') AS comps
FROM confederations AS c
LEFT JOIN media_relationships AS mr
ON mr.related_object_id = c.id
AND mr.related_object_table = 'confederations'
LEFT JOIN media AS m
ON m.id = mr.media_id
INNER JOIN countries AS cnt
ON cnt.confederations_id = c.id
INNER JOIN competitions AS cmp
ON cmp.countries_id = cnt.id
AND cmp.active = 1;
I am not proficient with Joins.
Basically, the result i am expecting is: For each Confederation (table C) I want that confederations name, abbreviation, active status (active), last modified date, modified by; from the Media Relationship table (table MR) I want the image id associated with that confederation so I can use that id to grab the image name and image slug for the confederations primary image from the Media table (M).
Now I also want the total number of Competitions (table CMP) for a given Confederation. Competitions are stored with a Country ID that is tied to the primary key ID of a country in the Countries Table (table CNT). Each Country in table CNT has a Confederations ID. So to get the total number of Competitions per Confederation I am 'trying' to get all Countries within their respective Confederation by CONFEDERATIONS_ID in table CNT, then foreach confederation I want select all the competitions from table CMP with matching COUNTRIES_ID from the group of country id's for that given confederation. (At this point i think i am confusing myself with how to get what i want)
Somehow I am getting the CORRECT NUMBER of competitions, but I am getting duplicate Confederations as results. For Example I am getting something similar to this (assume I have 3 different confederations with 2, 1, and 3 competitions respectively):
Competitions 1 : name 1 | abbreviation 1 | image 1 | total competitions = 2;
Competitions 1 : name 1 | abbreviation 1 | image 1 | total competitions = 1;
Competitions 1 : name 1 | abbreviation 1 | image 1 | total competitions = 3
What am i doing wrong?
Through trial and error, I actually solved this on my own. I came back to post my answer and see Degan's answer, and though it is written differently than mine I think its very close to what I ended up with:
SELECT
cnf.id AS confed_id, cnf.name AS confed_name, cnf.abbreviation AS
confed_abbr, cnf.active AS confed_active, cnf.modified_by AS
confed_mod_by, cnf.last_modified AS confed_last_mod,
COUNT(cnt.id) AS total_countries,
COUNT(cmp.id) AS total_comps,
mr.media_id, mr.related_object_table, mr.related_object_id,
mr.primary_img,
m.orig_name AS img_name, m.unique_name AS img_slug, m.file_type AS file_type
FROM confederations AS cnf
LEFT JOIN media_relationships AS mr
ON mr.related_object_id = cnf.id AND mr.related_object_table = 'confederations'
LEFT JOIN media AS m
ON m.id = mr.media_id
LEFT JOIN countries AS cnt
ON cnt.confederations_id = cnf.id AND cnt.active = 1
LEFT JOIN competitions AS cmp
ON cmp.countries_id = cnt.id AND cmp.active = 1
GROUP BY cnf.id
So farthis seems to be giving me results i can use. I am not certain if my choice of Left Join for all my joins is in fact giving me everything i need (it SEEMS to be) and whether this will omit/add records once the tables get larger. If anyone can point out a problem in my query and my choice of using Left Join as opposed to a combination of LEFT and INNER JOINs as Degan did, that would be helpful.
When aggregating you need to group by.
Perhaps this is close to what you are looking for:
SELECT c.id AS id
, c.name AS name
, c.abbreviation AS abbr
, m.orig_name AS img_name
, SUM('cmp.id') AS comps
FROM confederations AS c
LEFT JOIN media_relationships AS mr
ON mr.related_object_id = c.id
AND mr.related_object_table = 'confederations'
LEFT JOIN media AS m
ON m.id = mr.media_id
INNER JOIN countries AS cnt
ON cnt.confederations_id = c.id
INNER JOIN competitions AS cmp
ON cmp.countries_id = cnt.id
AND cmp.active = 1
GROUP BY c.id AS id
, c.name AS name
, c.abbreviation AS abbr
, m.orig_name AS img_name
I want to show the conclusion of all users.
I have 3 tables.
table post
post_id(index) user_id
1 1
2 3
3 3
4 4
table photo
photo_id(index) user_id
1 2
2 4
3 1
4 1
table video
photo_id(index) user_id
1 4
2 4
3 3
4 3
and in table user
user_id(index) user_name
1 mark
2 tommy
3 john
4 james
in fact, it has more than 4 rows for every tables.
I want the result like this.
id name post photo videos
1 mark 1 2 0
2 tommy 0 1 0
3 john 2 0 2
4 james 1 1 2
5 .. .. .. ..
Code below is SQL that can work correctly but very slow, I will be true appreciated if you help me how it using LEFT JOIN for it. Thanks.
SQL
"select user.*,
(select count(*) from post where post.userid = user.userid) postCount,
(select count(*) from photo where photo.userid = user.userid) photoCount,
(select count(*) from video where video .userid = user.userid) videoCount
from user order by user.id"
(or ORDER BY postCount, photoCount or videoCount ASC or DESC as i want )
I done researched before but no any helped me.
SELECT u.user_id,
u.user_name,
COUNT(DISTINCT p.post_id) AS `postCount`,
COUNT(DISTINCT ph.photo_id) AS `photoCount`,
COUNT(DISTINCT v.video_id) AS `videoCount`
FROM user u
LEFT JOIN post p
ON p.user_id = u.user_id
LEFT JOIN photo ph
ON ph.user_id = u.user_id
LEFT JOIN video v
ON v.user_id = u.user_id
GROUP BY u.user_id
ORDER BY postCount;
Live DEMO
Your method of doing this is quite reasonable. Here is your query:
select user.*,
(select count(*) from post where post.userid = user.userid) as postCount,
(select count(*) from photo where photo.userid = user.userid) as photoCount,
(select count(*) from video where video.userid = user.userid) as videoCount
from user
order by user.id;
For this query, you want the following indexes:
post(userid)
photo(userid)
video(userid)
user(id)
You probably already have the last one, because user.id is probably the primary key of the table.
Note that a left join approach is a bad idea in this case. The three tables -- posts, photos, and videos -- are independent of each other. If a user has five of each, then joining them together would produce 125 intermediate rows. If a user has fifty of each, it would be 125,000 -- a lot of extra processing.
Your answer is probably slow as it is using a correlated sub-query i.e. the sub query is running once for each user_id (unless the optimizer is doing something smart - which shouldn't be counted on).
You could use a left outer join and count or use something temporary like:
SELECT u.user_id,
u.user_name,
ph.user_count AS 'photoCount',
p.user_count AS 'postCount',
v.user_count AS 'videoCount'
FROM user u
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM photo
GROUP BY user_id
) ph
ON ph.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM post
GROUP BY user_id
) p
ON p.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM video
GROUP BY user_id
) v
ON v.user_id=u.user_id
There are pros and cons for both (depending on indexes). Always have a look at the query plan (using EXPLAIN for MySQL).
I don't really know how to even search for resolution of this problem, didn't find anything specific, so here goes...
I have four tables, let's simplify them:
players
=======
id name surname
1 John Arbuckle
2 Walter White
3 Don Draper
4 Louis CK
5 Tyrion Lannister
6 Abed Nadir
sports
======
id sport
1 football
2 handball
positions
=========
id name sport_id
1 goalie 1
2 defense 1
3 attack 1
4 goalie 2
5 pivot 2
6 wing 2
7 center 2
player_position
===============
player_id position_id
1 1
1 2
1 5
2 7
2 5
3 2
4 2
5 1
5 3
6 7
6 5
So, player can play multiple sports and on multiple positions. First, I have to display list of players for a certain sport, including a column with positions they play.
What I started with is JOIN statement where I'd join those tables and have multiple rows for each player ID. That's close, but not very correct. And what I need to get is a tables like this:
FOOTBALL
ID name surname position
1 John Arbuckle PHP array(goalie,defense)
HANDBALL
ID name surname position
1 John Arbuckle PHP array(pivot)
EDIT:
So what I was looking for was GROUP_CONCAT().
Thanks guys!
select p.id, p.name, p.surname, group_concat(po.name)
from players p
inner join player_position pp on pp.player_id = p.id
inner join positions po on po.id = pp.position_id
inner join sports s on s.id = po.sport_id
where s.sport = 'football'
group by p.id
See this SQLFiddle example
For football:
SELECT players.name, players.surname, positions.name
FROM players, sports, positions, player_position
WHERE sports.id = 1 AND positions.sport_id = sports.id AND payer_position.position_id = positions.id AND players.id = player_position.player_id;
For Handball:
SELECT players.name, players.surname, positions.name
FROM players, sports, positions, player_position
WHERE sports.id = 2 AND positions.sport_id = sports.id AND payer_position.position_id = positions.id AND players.id = player_position.player_id;
I'm not sure if this is foolproof (not tested) but…
SELECT pp.`player_id` AS 'ID',s.`id` AS 'sport_id',s.`sport`,ps.`name` AS 'position',pl.`name`,pl.`surname` FROM `sports` s
INNER JOIN `positions` ps ON s.`id`=ps.`sport_id`
INNER JOIN `player_position` pp ON pp.`position_id`=ps.`id`
INNER JOIN `players` pl ON pl.`id`=pp.`player_id`
ORDER BY s.`id`,pp.`player_id`,ps.`id`
Here's a more detailed version:
SELECT
s.`id` AS 'sport_id',s.`sport`,
ps.`id` AS 'position_id',ps.`name` AS 'position',
pl.`id` AS 'player_id',pl.`name`,pl.`surname`
FROM `sports` s
INNER JOIN `positions` ps ON s.`id`=ps.`sport_id`
INNER JOIN `player_position` pp ON pp.`position_id`=ps.`id`
INNER JOIN `players` pl ON pl.`id`=pp.`player_id`
ORDER BY s.`id`,pp.`player_id`,ps.`id`
my problem analogy is like this:
table: place
id title branch
===============================
1 pizza store california
2 pizza store manhattan
3 coffee shop california
4 pizza store texas
5 cookie store new york
table: rating
id place_id rating
================================
1 1 3.5
2 2 5.0
3 2 4.2
4 2 5.0
5 5 4.0
i use query:
SELECT F.id AS id, F.title AS title, G.rating
FROM place F
JOIN rating G ON F.id = G.place_id
GROUP BY F.title
the display will be :
id title rating
===========================
1 pizza store 3.5
3 coffee shop -
5 cookie store 4.0
what i want is to sort title that has rating with the maximum one, in this case i want it to display pizza store with rating 5 and id 2. Is it possible to insert some subquery inside GROUP BY ?
Thanks in advance!!
try
SELECT F.id , F.title, s.Maxrating
FROM place F
INNER JOIN (SELECT id,Max(rating) as MaxRating FROM rating GROUP BY place_id ) s
ON s.id = F.id
SELECT F.id AS id, F.title AS title, max(G.rating)
FROM place F, rating G
where F.id = G.place_id(+)
group by f.id, f.title