I have a join that works exactly as expected, except any and all fields selected from the 'right' table are returned blank when they definitely are not.
SELECT score.recipient, score.amount, u.* FROM score
LEFT JOIN `users` AS u ON score.recipient = u.id AND u.team_id = ?
WHERE UNIX_TIMESTAMP(score.date) > ?
I don't actually need the entire users table, only users.email - but no fields work. The result set looks like this (sample):
[0] => stdClass Object ( [recipient] => 1 [amount] => 1 [id] => [fname] => [lname] => [nickname] => [email] => [phone] => [reg_key] => )
[1] => stdClass Object ( [recipient] => 103 [amount] => -1 [id] => [fname] => [lname] => [nickname] => [email] => [phone] => [reg_key] => )
All of the fields listed are in fact populated.
Any help would be appreciated! I'm at a loss.
Your join condition / where clause is broken if replacing the left join with an inner join returns an empty result set.
Try this (without bind variables and their conditions) and see if it returns any values:
SELECT score.recipient, score.amount, u.* FROM score
LEFT JOIN `users` AS u ON score.recipient = u.id
If that's the case, then look at the values for team_id / score.date you get - I bet you're using a combination of bind values that simply does not exist in your tables.
Related
Edit: Using MySQL.
In this example I have a Posts table, a Users table, a Tagged_Posts table, and a Tags table.
The Posts table has a foreign key for user_id that corresponded to the Users table and id column.
The Tagged_posts table has two foreign keys, one for the tag_id and one for the post_id
The Tags table just has an id and a slug.
I'm trying to query posts and have all data related to that post returned, i.e The Post data, the user's data whom the post, and what tags belong to that post.
A single post can have many tags.
This is the SQL query I'm using:
$sql = "SELECT posts.title, users.name, users.handle, users.email, tags.slug as tags
from posts
INNER JOIN users ON posts.user_id = users.id
INNER JOIN tagged_posts ON posts.id = tagged_posts.post_id
INNER JOIN tags ON tagged_posts.tag_id = tags.id";
Since this particular post has 3 tags associated with it, the query returns the same post 3 times with different values listed for tag. See below:
Array
(
[0] => Array
(
[title] => This is my first Post!
[name] => exampleuser
[handle] => example
[email] => example#gmail.com
[tags] => database-design
)
[1] => Array
(
[title] => This is my first Post!
[name] => exampleuser
[handle] => example
[email] => example#gmail.com
[tags] => sql
)
[2] => Array
(
[title] => This is my first Post!
[name] => exampleuser
[handle] => example
[email] => example#gmail.com
[tags] => php
)
)
Am I able to do a single query and get everything related to the post?
You want to concatenate the results together. For instance, in MySQL, you would do:
select p.title, u.name, u.handle, u.email, group_concat(t.slug) as tags
from posts p join
users u
on p.user_id = u.id join
tagged_posts tp
on p.id = tp.post_id join
tags t
on tp.tag_id = t.id
group by p.title, u.name, u.handle, u.email;
I am trying to get a count of apps for a user, using LEFT JOIN. It needs to return users regardless of whether they have apps, but the query is returning an empty record with 0 apps when no users are present.
SELECT u.*, COUNT(a.id) AS apps_working
FROM users u
LEFT JOIN apps a ON (u.id = a.user_id)
WHERE u.company_id = :company_id
AND u.account_type = 3
EDIT: When there are no users present, the results look like this:
Array
(
[0] => Array
(
[id] =>
[company_id] =>
[user_login] =>
[user_password] =>
[first_name] =>
[last_name] =>
[user_hash] =>
[user_slug] =>
[date_joined] =>
[last_login] =>
[account_type] =>
[status] =>
[apps_working] => 0
)
)
This is a query that is ALWAYS going to return a value because count(*) will always return something. If you don't want to see that, add a case statement to trap 0 and return null.
Try this code:
SELECT u.*, COUNT(IFNULL(a.id,0)) AS apps_working
FROM users u
LEFT JOIN apps a ON (u.id = a.user_id)
WHERE u.company_id = :company_id
AND u.account_type = 3
This is a left join query. So if there is no user satisfies conditions of company_id and account_type, there is no thing for joining and there is no thing in result.
how to join this in single query any help to combine these two queries as one without looping,
$today_date = mktime(0, 0, 0, $mon, $day-1, $year);
SELECT * FROM (`lead_follow_up`) LEFT JOIN `leads` ON `leads`.`id` = `lead_follow_up`.`lead_id` WHERE `date` <= $today_date GROUP BY `lead_follow_up`.`lead_id` ORDER BY `lead_follow_up`.`date` DESC
from the above query i get array $previou
$previou= Array
(
[0] => stdClass Object
(
[id] => 1
[lead_id] => 75943
[date] => 1438930800
[updated_on] => 1438884890
)
[1] => stdClass Object
(
[id] => 2
[lead_id] => 75943
[date] => 1416459600
[updated_on] => 1415901523
),
[2] => stdClass Object
(
[id] => 3
[lead_id] => 75943
[date] => 1416459600
[updated_on] => 1415901523
),....etc
);
foreach($previou as $key => $p):
$q = "SELECT `id` FROM (`lead_follow_up`) WHERE `lead_id` = '".$p->id."' AND `date` > '".$p->date."' ORDER BY `updated_on` DESC ";
if(!$this->db->query($q)){
$previouData[$key] = $p;
$pCount++;
}
endforeach;
how to join this in single query any help to combine these two queries as one without looping,
Your queries don't make much sense. For a start your first query has a GROUP BY lead_follow_up.lead_id but no aggregate functions. So in MySQL that will return one row for each value of lead_id (which row it returns is not defined).
Yet your array of sample data has multiple rows per lead_id so cannot have come from the query.
You are also LEFT OUTER JOINing the leads table, yet it doesn't seem to make sense to have a lead_follow_up which doesn't relate to a lead. As such you may as well use an INNER JOIN.
I am going to assume that what you want is a list of leads / lead_follow_ups and for each one a couple of all the follow ups after that particular follow up. That would give you something like this (making loads of assumptions as I do not know your table structure):-
SELECT leads.id AS lead_id,
lead_follow_up.id
lead_follow_up.`date`,
lead_follow_up.updated_on,
COUNT(lead_follow_up_future.id) AS future_lead_count
FROM leads
INNER JOIN lead_follow_up ON leads.id = lead_follow_up.lead_id
LEFT OUTER JOIN lead_follow_up AS lead_follow_up_future ON leads.id = lead_follow_up.lead_id AND lead_follow_up_future.`date` > lead_follow_up.`date`
WHERE lead_follow_up.`date` <= $today_date
GROUP BY leads.id AS lead_id,
lead_follow_up.id
lead_follow_up.`date`,
lead_follow_up.updated_on
ORDER BY lead_follow_up.date DESC
I have a working SQL statement, but there is one issue within it I can't solve.
When I left join my table sites_photos there can be multiple matches on sp.sites_id = s.id, but I want the table to only return 1. Is this possible.
SELECT s.*, sp.photo
FROM sites s
LEFT JOIN sites_photos sp
ON sp.sites_id = s.id
My output: 2 times id 30, but with different photo paths, I only want 1 returned for that id, or both bundled in one array.
Array
(
[0] => Array
(
[id] => 30
[url] => www.test.nl
[name] => Aleve
[date] => 2014-08-16
[cms_active] => Y
[archive] => N
[photo] => 2014080812365920120214103601number_1.jpg
)
[1] => Array
(
[id] => 30
[url] => www.test.nl
[name] => Aleve
[date] => 2014-08-16
[cms_active] => Y
[archive] => N
[photo] => 20140811021102news.jpg
)
)
You can do so,by using GROUP_CONCAT which will concatenate all the photos per site by and produces comma separated list of photos then you can use SUBSTRING_INDEX over result of GROUP_CONCAT to pick one photo,you can also add the criteria of order by in GROUP_CONCAT as GROUP_CONCAT(sp.photo ORDER BY sp.id DESC)
SELECT s.*, SUBSTRING_INDEX(GROUP_CONCAT(sp.photo),',',1) photo
FROM sites s
LEFT JOIN sites_photos sp
ON sp.sites_id = s.id
GROUP BY s.id
the tables are:
units (id,...) // approx' 10,000 units
contracts(id, unit_id, active, ...) // approx 50,000 records
I want to get all the units, that have no contract attached to them (and contracts.active=true).
My ideas are:
Using NOT IN:
select * from units
where id NOT IN(select unit_id from contracts where contracts.active = true)
Or:
select * from units u
left join contracts c
on c.unit_id = u.id
where c.unit_id is null
and, if there is a native way to do it in cake, please show me the light :)
thanks
Depending on what your other joins are, the NOT IN could give you bad performance. I would suggest the following SQL query:
SELECT * FROM units AS u
LEFT JOIN contracts AS c
ON (c.unit_id = u.id AND c.active = 1)
WHERE c.id IS NULL
According to the cakephp documentation:
Cake can also check for null fields. In this example, the query will return records where the post title is not null:
array ("NOT" => array (
"Post.title" => null
)
)
So depending on how your models are setup, this may work for you:
$joins = array(('table' => 'contracts',
'alias' => 'Contracts',
'type' => 'LEFT',
'conditions' => array('Contracts.active' => 0)));
$conditions = array('Contracts.id' => NULL);
$units = $this->Units->find('all', array('joins' => $joins, 'conditions' => $conditions));