mysql Join showing wrong result PHP - php

I have following three tables:
taxi:
id shopid taxiId status
1 20 1 1
2 20 2 1
3 20 3 2
4 20 4 1
5 21 1 1
...
preBooking:
id shopid taxiId status
1 20 1 booked
2 20 3 booked
usrBooking:
id shopid taxiId status
1 20 2 booked
2 20 4 booked
Now I want to get all records from taxi table ( for example shop id=20), and matching record of preBooking and usrBooking table.
For example I want to get records like this (if i pass shop id 20 in parameter)
id shopid taxiId preBookingstatus usrBookingstatus
1 20 1 Booked Null
2 20 2 Null Booked
3 20 3 Booked Null
4 20 4 Null Booked
I tried with following code but not working correctly,showing wrong results
$shopid="20";
$this->db->select('t.taxiId,ub.status as usrBookingstatus ,pb.status as preBookingstatus ');
$this->db->from('taxi t');
$this->db->join('usrBooking ub', 'ub.taxiId=t.taxiId','LEFT OUTER');
$this->db->join('preBooking pb', 'pb.taxiId=t.taxiId','LEFT OUTER');
$this->db->where('t.shopid', $shopid);
$this->db->order_by('t.taxiId', 'ASC');

First I am unsure what is this:
$this->db->where('c.salon_id', $shopid);
There is no table "c" in the FROM of the query and "salon_id" is not mentioned in the example data above. This makes the query invalid and you can't run it. Maybe this is the issue. Probably you should change it to:
$this->db->where('t.shopid', $shopid);
Also you are missing some columns in the SELECT. The full query should be:
SELECT t.id, t.shopid, t.taxiId, pb.status as preBookingstatus, ub.status as usrBookingstatus
FROM taxi t
LEFT JOIN usrBooking ub ON ub.taxiId=t.taxiId
LEFT JOIN preBooking pb ON pb.taxiId=t.taxiId
WHERE t.shopid = 20
ORDER BY t.taxiId ASC;
Or with your PHP code:
$shopid="20";
$this->db->select('t.id, t.shopid, t.taxiId, pb.status as preBookingstatus, ub.status as usrBookingstatus');
$this->db->from('taxi t');
$this->db->join('usrBooking ub', 'ub.taxiId=t.taxiId','LEFT OUTER');
$this->db->join('preBooking pb', 'pb.taxiId=t.taxiId','LEFT OUTER');
$this->db->where('t.shopid', $shopid);
$this->db->order_by('t.taxiId', 'ASC');

It seems as if your select statement is missing a few columns. Change
$this->db->select('t.taxiId,ub.status as usrBookingstatus ,pb.status as preBookingstatus ');
to
$shopid=20;
$this->db->select('t.id, t.shopid, t.taxiId,pb.status as preBookingstatus , ub.status as usrBookingstatus ');
$this->db->from('taxi as t');
$this->db->join('usrBooking as ub', 't.taxiId=ub.taxiId','LEFT');
$this->db->join('preBooking as pb', 't.taxiId=pb.taxiId','LEFT');
$this->db->where('t.shopid', $shopid);
$this->db->order_by('t.taxiId', 'ASC');

Related

Mysql: Duplicate and incorrect output when using join

I have 4 tables on which I need to use a join. The query is returning duplicate rows. However for simplicity I will post my question with just 2 tables as the problem still exits even with 2 tables. Tables are called as product_offer and promo. The structures are as below
product_offer table:
id product_id offer_id store_id validity
1 1 1 1 2016-12-12 00:00:00
2 2 2 1 2016-12-12 00:00:00
3 3 3 1 2016-12-12 00:00:00
4 1 4 1 2016-12-12 00:00:00
promo table:
id product_id store_id name
1 1 1 Buy 1 Get 1 free
2 2 1 10% off
3 3 1 $10 off
4 1 1 Get Chips Free
I am trying to fetch all the offers for a particular product-store combination. I am expecting to get this
product_id offer_id store_id name
1 1 1 Buy 1 Get 1 Free
1 4 1 Get Chips Free
But When I run this query I am getting the below output which is incorrect and with duplicate rows
SELECT po.product_id, po.offer_id,po.store_id,o.name
from product_offer po
left join promo o on po.product_id = o.product_id
where po.product_id = 1 and po.store_id = 1
product_id offer_id store_id name
1 1 1 Buy 1 Get 1 Free
1 4 1 Buy 1 Get 1 Free
1 1 1 Get Chips Free
1 4 1 Get Chips Free
I also want to improve the query and use concat(using ~ as separator) to only return one row per product_id as below:
product_id offer_id store_id name
1 1~4 1 Buy 1 Get 1 free~Get Chips Free
You want to use a GROUP BY, what does it, it takes the column you chose puts them together to avoid duplicate results where data in that column matches
SELECT po.product_id, po.offer_id,po.store_id,o.name
from product_offer po
left join promo o on po.product_id = o.product_id
where po.product_id = 1 and po.store_id = 1
GROUP BY product_id
In order to concatenate them, there is the option of GROUP_CONCAT, you can read more at http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
use Group by with GROUP_CONCAT
SELECT po.product_id,GROUP_CONCAT(DISTINCT po.offer_id SEPARATOR '~') offer_id
,po.store_id,GROUP_CONCAT(DISTINCT o.name SEPARATOR '~') name
from product_offer po
left join promo o on po.product_id = o.product_id
where po.product_id = 1 and po.store_id = 1
Group by product_id
I realized I was doing the Join ON the wrong column. When I changed the join on offer_id from product_offer and id on promo it worked nicely.
SELECT po.product_id, group_concat(po.offer_id SEPARATOR '~') offer_id, po.store_id ,group_concat(o.name SEPARATOR '~') offer
FROM product_offer po
LEFT JOIN
promo o ON po.offer_id = o.id
WHERE
po.product_id = 1 and po.store_id = 1
I think you need to group by offer_id
SELECT po.product_id,GROUP_CONCAT(po.offer_id SEPARATOR '~') offer_id,po.store_id,o.name
from product_offer po
left join promo o on po.product_id = o.product_id
where po.product_id = 1 and po.store_id = 1
Group by offer_id

how to select records based on count of column field

I have a scenario that a query who will work like select records based on status = 1 with highly number of records found in database.
suppose i want to select artists who have max number of status = 1 with their names fetch from other table.
another problem is my query is repetiting records.
my query:
SELECT order.status,
order.artist_id,
web_user.uFname,
web_user.uLname,
web_user.uID
FROM `order`
INNER JOIN `web_user`
ON web_user.uID = order.artist_id
HAVING order.status = '1'
my record set i am getting:
status artistid uFname uLaname uID
1 14 Pitbull Armando 14
1 14 Pitbull Armando 14
1 13 Enrique Iglesias 13
1 15 Robyn Rihanna 15
1 15 Robyn Rihanna 15
1 15 Robyn Rihanna 15
i simple want:
downloadtimes artistid uFname uLaname uID
2 14 Pitbull Armando 14
1 13 Enrique Iglesias 13
3 15 Robyn Rihanna 15
please enhanced my query.
You can use COUNT()
SELECT
COUNT(*) AS downloadtimes ,
order.artist_id,
web_user.uFname,
web_user.uLname,
web_user.uID
FROM `order`
INNER JOIN `web_user` ON web_user.uID = order.artist_id
WHERE order.status = '1'
GROUP BY order.artist_id
you should use the count
like:
COUNT(*) AS downloadtimes
you should just add the like you full code:
SELECT
COUNT(*) AS downloadtimes ,
order.artist_id,
web_user.uFname,
web_user.uLname,
web_user.uID
FROM `order`
INNER JOIN `web_user` ON web_user.uID = order.artist_id
WHERE order.status = '1'
GROUP BY order.artist_id
and refer this following link:
SQL COUNT

mysql join and sum problems

Im having some trouble with this.
Here's an example of my tables.
Booking
id zone_id name excursion_id
1 2 1
2 1 1
3 2 1
The table where I have the quantities
booking_price
id_booking id_price quantity
1 1 2
1 2 3
2 1 1
2 2 0
3 1 2
3 2 3
Here the zone table
Zone
id Name
1 a
2 b
3 c
So I want to have a table like that
Zone_id Quantity
1 1
2 10
3 0
The problem is when im joining tables and filtering by excursion_id im not getting ALL the zones.
I want to know how many people goes in each zone.
I think better way of doing it is
select z.id, coalesce(sum(bp.quantity),0) as quantity
from Booking b
right join Zone z on z.id = b.zone_id AND b.excursion_id = 1
left join booking_price bp on bp.id_booking = b.id
group by z.id
demo http://sqlfiddle.com/#!2/771f5/13
You could use a query like:
SELECT zone.id as zone_id,
sum(quantity) as Quantity
FROM zone
LEFT JOIN Booking on Booking.zone_id = zone.id
LEFT JOIN Excursion on Excursion.id_booking = Booking.id
GROUP BY zone.id

I want the last row of all players in a specific month+year

Here is a simplified version of my sql table of 2 months (ORDERED BY DATE):
player_id |
date |
score
1 2011-05-25
1200
2 2011-05-25
3400
3 2011-05-26
3200
4 2011-05-26
4400
1 2011-05-28
1000
2 2011-05-28
2000
3 2011-05-29
3000
4 2011-05-29
4000
1 2011-06-24
1300
2 2011-06-24
2500
3 2011-06-24
5000
4 2011-06-24
3000
Basically, I want a query that shows the last score of all players in a specific month/specific year.
Example:
If I want the final scores of all players in the month 05, te result
would be:
1 2011-05-28 1000
2 2011-05-28 2000
3 2011-05-29 3000
4 2011-05-29 4000
My sql query so far:
SELECT m1.* FROM table m1
LEFT JOIN table m2 ON (m1.player_id = m2.player_id AND m1.date < m2.date)
WHERE m2.date IS NULL
AND month(m1.date) = 05
AND year(m1.date) = 2011
ORDER BY score DESC);
This doesn't seem to show all players, only players that didn't play in the months after 05. Where do I add the date select?
**EDIT
John Nestoriak's answer bellow did the trick for me :)
I think he's referring to the technique shown here: Retrieving the last record in each group
With the additional constraint of he doesn't want the last record but the last record in a given month.
Oddly enough you have to give that additional constraint twice, once in the join condition and again to filter the results. This should do it for you.
SELECT m1.* FROM table m1
LEFT JOIN table m2 ON
(m1.player_id = m2.player_id AND m1.date < m2.date
AND m2.date < '2011-06-01')
WHERE m2.date IS NULL AND month(m1.date) = 5 AND year(m1.date) = 2011
Assuming that the (player_id, date) combination in Unique:
SELECT
t.*
FROM
TableX AS t
JOIN
( SELECT
player_id
, MAX(date) AS maxDate
FROM
TableX
WHERE
date BETWEEN '2011-05-01'
AND LAST_DAY('2011-05-01')
GROUP BY
player_id
) AS tg
ON
(tg.player_id, tg.maxDate) = (t.player_id, t.date)
ORDER BY
t.score DESC

Help with limiting a joined mysql database query

I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.

Categories