Why isn't this query working? - mysql

Here is the query in question:
SELECT e.id, e.name, u.x_account_username, ao.id
FROM x_evidence e
LEFT JOIN x_ambition_owner ao
ON e.ambition_id = ao.id
LEFT JOIN x_user u
ON ao.profile_id = u.id
WHERE e.updated BETWEEN '2014-03-19 10:16:00' AND '2014-03-19 11:16:00'
Can anyone see what I'm doing wrong?
Evidence table:
id ambition_id name updated
1jk 2ef abc 2014-03-19 10:33:31
Ambition owner table:
id ambition_id profile_id
1op 2ef 1abc
User table:
id x_account_username
1abc rex hamilton
I want my returning to get:
the evidence id, name, user's name, the associated ambition id, between the times stated (but these could vary)
Thanks

One way it is not working is that the where clause is turning the first left join into an inner join. So, you would not be getting all rows from the query that you expect. In fact, you might not be getting any of them.
You can fix this by moving the condition into the on clause:
SELECT ao.id AS a_id, e.id AS e_id, e.name AS evidence_name,
u.x_account_username AS username, 'evidence_edit' AS type
FROM x_ambition_owner ao
LEFT JOIN x_evidence e
ON ao.id = e.ambition_id
AND e.updated BETWEEN '2014-03-19 10:16:00' AND '2014-03-19 11:16:00'
LEFT JOIN x_user u
ON ao.profile_id = u.id;
EDIT (by OP):
This is the query I will be using:
SELECT e.id, e.name, u.x_account_username AS username, a.ambition_id
FROM x_evidence e
LEFT JOIN x_ambition_owner a
ON e.ambition_id = a.ambition_id
LEFT JOIN x_user u
ON a.profile_id = u.id
WHERE e.updated BETWEEN '2014-03-19 10:00:00' AND '2014-03-19 11:16:00'

Related

SQL: Sum factor*value in a LEFT JOIN

I would like to get some information: I got a table called "invoices" and a table called "invoice_positions".
All personal information about a customer are stored in "invoices". All positions are stored in "invoice_positions".
Well, now I would like to know the total sum of all matching positions:
I got this invoice-entry:
id: 1
customer: 4
I got this invoice-positions-entry:
id: 1
invoiceid: 1
factor: 2
value: 5
id: 2
invoiceid: 1
factor: 1
value: 5
The result should be: 2*5+1*5 = 15
This is my query so far:
SELECT DISTINCT a.*,SUM(ip.factor * ip.value) as totalsum,om.orderid,o.userid as userid,c.lastname as customer_lastname, c.firstname as customer_firstname, c.company as customer_company,uc.name AS editor,created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
ORDER BY a.id asc
But my result is not 15 - it's 30.
you will no longer need the distinct with the group by.
a.* will have to be split into individual columns you want to return in results.
group by has been added below for known columns
.
SELECT a.*,SUM(ip.factor * ip.value) as totalsum,
om.orderid, o.userid as userid, c.lastname as customer_lastname,
c.firstname as customer_firstname, c.company as customer_company,
uc.name AS editor,
created_by.name AS created_by
FROM `o45_hero_invoices` AS a
LEFT JOIN o45_hero_invoices_positions AS ip ON ip.invoiceid=a.id
LEFT JOIN o45_hero_invoices_mapping AS om ON om.invoiceid=a.id
LEFT JOIN o45_hero_orders AS o ON o.id=om.orderid
LEFT JOIN o45_hero_customers AS c ON c.userid=o.userid
LEFT JOIN o45_users AS uc ON uc.id=a.checked_out
LEFT JOIN o45_users AS created_by ON created_by.id = a.created_by
WHERE (a.state IN (0, 1))
GROUP BY a.Field1, a.Field2, A.Field3...,
om.orderid, o.userid, c.lastname, c.firstname,
c.company, uc.name, created_by.name
ORDER BY a.id asc

Field list in ambiguous in join with 4 tables

Very confused why this is happening since I'm naming the specific tables as es and sub that it's complaining about (and I think that's how you fix that particular issue).
I've got:
users submissions_comments email_settings submissions tables
This query gives me what I want, but I now want to join this on my email_settings and submissions table which both have a user_id.
SELECT user_id,
submission_id,
comment,
users.*,
FROM submissions_comments
INNER JOIN
(SELECT submissions_comments.parent_id
FROM submissions_comments
WHERE id = 224) x ON submissions_comments.id = x.parent_id
LEFT JOIN users ON submissions_comments.user_id = users.id
Output:
user_id: 35
submission_id: 12
comment: fdasadfsdadfs
id: 35
email: bobcobb#gmail.com
username: bobcobb
name: Robert Cobb
about:
created: 2014-03-21 20:24:57
last_login: 2014-07-06 23:21:43
public_profile: 1
queued_photo: 0
But if I try to join on another table (which has a reference to a user_id) I get Column 'user_id' in field list is ambiguous
SELECT user_id,
submission_id,
comment,
users.*,
es.*,
sub.*
FROM submissions_comments
INNER JOIN
(SELECT submissions_comments.parent_id
FROM submissions_comments
WHERE id = 224) x ON submissions_comments.id = x.parent_id
LEFT JOIN users ON submissions_comments.user_id = users.id
LEFT JOIN submissions sub ON x.parent_id = sub.user_id
LEFT JOIN email_settings es ON x.parent_id = es.user_id;
As you can tell I'm joining all of these on the user_id returned from the inner select (e.g. x.parent_id).
You have to add the alias to the column name:
SELECT sub.user_id,...
SELECT submissions_comments.user_id,
submissions_comments.submission_id,
submissions_comments.comment,
users.*,
es.*,
sub.*
FROM submissions_comments
INNER JOIN
(SELECT submissions_comments.parent_id
FROM submissions_comments
WHERE id = 224) x ON submissions_comments.id = x.parent_id
LEFT JOIN users ON submissions_comments.user_id = users.id
LEFT JOIN submissions sub ON x.parent_id = sub.user_id
LEFT JOIN email_settings es ON x.parent_id = es.user_id;
you need to define which user_id you are referring on the select part as well.

Combined queries returns different results

The results of a query I created from two different queries is not returning the same results.
Query A
SELECT
c.fullname Course,
u.firstname First,
u.lastname Last,
u.id ID,
u.institution Company
FROM (mdl_scorm_scoes_track AS st)
JOIN mdl_user AS u ON st.userid=u.id
JOIN mdl_scorm AS sc ON sc.id=st.scormid
JOIN mdl_course AS c ON c.id=sc.course
Join mdl_user_enrolments AS uenr ON uenr.userid=u.id
Join mdl_enrol AS enr ON enr.id=uenr.enrolid
WHERE (
(st.value='incomplete' OR st.value='not attempted')
AND DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated)>60)
ORDER BY c.fullname, u.lastname,u.firstname, u.id
Query B
SELECT
c.fullname AS Course,
u.firstname AS Firstname,
u.lastname AS Lastname,
u.id AS ID,
u.institution AS Company,
IF (u.lastaccess = 0,'never',
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d')) AS dLastAccess
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM mdl_user_lastaccess WHERE userid=u.id AND courseid=c.id) AS CourseLastAccess
FROM mdl_user_enrolments AS ue
JOIN mdl_enrol AS e ON e.id = ue.enrolid
JOIN mdl_course AS c ON c.id = e.courseid
JOIN mdl_user AS u ON u.id = ue.userid
LEFT JOIN mdl_user_lastaccess AS ul ON ul.userid = u.id
WHERE ul.timeaccess IS NULL AND (DATEDIFF(NOW(), FROM_UNIXTIME(ue.timecreated))>60)
ORDER BY u.id, c.fullname
I have combined them into Query C
SELECT
c.fullname AS Course,
u.firstname AS Firstname,
u.lastname AS Lastname,
u.id AS IDNumber,
u.institution AS Institution,
IF (u.lastaccess = 0,'never',
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d')) AS dLastAccess
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM mdl_user_lastaccess WHERE userid=u.id AND courseid=c.id) AS CourseLastAccess
FROM mdl_user_enrolments AS ue
JOIN mdl_enrol AS e ON e.id = ue.enrolid
JOIN mdl_course AS c ON c.id = e.courseid
JOIN mdl_user AS u ON u.id = ue.userid
LEFT JOIN mdl_user_lastaccess AS ul ON ul.userid = u.id
WHERE (ul.timeaccess IS NULL OR ue.userid IN
(SELECT u.id
FROM (mdl_scorm_scoes_track AS st)
JOIN mdl_scorm AS sc ON sc.id=st.scormid
WHERE c.id=sc.course AND st.userid=u.id AND (st.value='incomplete' OR st.value='not attempted')
)
)AND (DATEDIFF(NOW(), FROM_UNIXTIME(ue.timecreated))>60)
ORDER BY c.fullname, u.lastname,u.firstname
I have not found where my logic is incorrect in Query C. Query C is adding an incorrect record not found by either A or B and duplicating entries in a couple of cases.
I would like some pointers on where my logic on combining the 2 went astray.
I fixed the commas in this post, the actual queries did have them.
My intent is to list all users that have been enrolled into a course but within a given timeframe, have not logged into the system, accessed the course and finally have not completed the activity in the course.
So the logic I am looking for is:
If the user has not logged in within 60 days - display name
If logged in but has not accessed the course within 60 days - display name
If logged in and has accessed the course but has not completed the course activity- display name
Query A does list all users that started the activity but have not completed within 60 days
Query B does list all users that have not logged in or accessed the course within 60 days
In trying to combine the 2 queries to satisfy all 3 conditions is where I am having problems. I first tried a UNION but could not get it to work.
You are not selecting from the same worlds in both queries. Query A has 6 tables it is selecting from and Query B has 5 (its missing the mdl_scorm table) and your Query C has the 5 tables that Query B has. So now your scope for Query A has changed. That extra table could have been eliminating rows in the join that are now appearing in Query C for the selects of A.
I would check Query A with the mdl_scorm table missing from the query and you probably have a different result size.
Think of it as
select COLUMNS from TABLES where FILTERS; TABLES (universe of data) needs to be the same for both queries for you to just join the COLUMNS and FILTERS (expand selection and limit results)

MySQL how to check if selected column is null before woking with him?

I am working on expanding user profiles for my project, adding more info. I was just adding countries, when I hit a problem. This is my query for selecting all profile data needed:
SELECT c.*, d.username, d.email, e.country_name
FROM user_profiles c, users d, country e
WHERE c.user_id = ".$id." AND d.id = ".$id."
AND e.country_name = (SELECT country_name FROM country WHERE id = c.country_id)
c.* should select all columns from user_profiles.
The $id is an id of user selecting wich profile should be returned. The problem is, keeping registration as simple as possible, I dont have a country selector there. So when this query comes in action, column country_id from user_profiles is empty, that means when I want to return the country_name, the query result is empty, so no profile data is returned.
I have tried to rewrite this with CASE or LEFT JOIN, but I think I am missing something. I want to find if country_id is not null, when it is not, select also country_name with this country_id. Any ideas?
Thank you kindly for responds.
You can use a LEFT JOIN, but it would be so much easier to do that if you started off by using the cleaner and more modern JOIN syntax:
SELECT c.*, d.username, d.email, e.country_name
FROM user_profiles c
JOIN users d ON d.id = c.id
JOIN country e ON e.country_id = c.country_id
WHERE c.user_id = 42
Now to solve your problem you can just add LEFT:
LEFT JOIN country e ON e.country_id = c.country_id
Full query:
SELECT c.*, d.username, d.email, e.country_name
FROM user_profiles c
JOIN users d ON d.id = c.id
LEFT JOIN country e ON e.country_id = c.country_id
WHERE c.user_id = 42
Related
Why isn't SQL ANSI-92 standard better adopted over ANSI-89?
Before I even start thinking about your current problem, can I just point out that your current query is a mess. Really bad. It might work, it might even work efficiently - but it's still a mess:
SELECT c.*, d.username, d.email, e.country_name
FROM user_profiles c, users d, country e
WHERE d.id = ".$id."
AND d.id = c.user_id
AND e.id = c.country_id;
I have tried to rewrite this with CASE or LEFT JOIN
But you're not going to show us your code?
One solution would be to use a sub select against each row in user_profiles/users:
SELECT c.*, d.username, d.email,
(SELECT e.country_name
FROM country e
WHERE AND e.id = c.country_id LIMIT 0,1) AS country_name
FROM user_profiles c, users d
WHERE d.id = ".$id."
AND d.id = c.user_id;
Alternatively, use a LEFT JOIN:
SELECT c.*, d.username, d.email, e.country_name
FROM user_profiles c
INNER JOIN users d
ON d.id = c.user_id
LEFT JOIN country e
ON e.id = c.country_id
WHERE d.id = ".$id.";

Why doesn't my query return any results?

Why does this sql query only show results if they only have a row in users_warnings?
SELECT
u.id,
uw.warning
FROM
users u
INNER JOIN users_warnings uw ON (
u.id = uw.uID
)
LIMIT 21
I wish to show all users, but also grab the column "warning" in users_warnings, if any.
An INNER JOIN only returns something if there is data in both tables.
Try a LEFT JOIN instead:
SELECT u.id, uw.warning FROM users u
LEFT JOIN users_warnings uw ON (u.id = uw.uID)
LIMIT 21
Because you're using an inner join, which requires a row to exist on the joined table. Try the following:
SELECT
u.id,
uw.warning
FROM
users u
LEFT JOIN users_warnings uw ON (
u.id = uw.uID
)
LIMIT 21
Change your inner join for a left join, as so:
SELECT u.id, uw.warning FROM users u
LEFT JOIN users_warnings uw ON (u.id = uw.uID)
LIMIT 21
SELECT
u.id,
IFNULL(uw.warning,'') warning
FROM
(SELECT id FROM users LIMIT 21) u
LEFT JOIN users_warnings uw
ON u.id = uw.uID
;
Should be a LEFT JOIN not INNER JOIN
Refactored the query to get first 21 users before attempting a JOIN (faster query)
Defaulted warning to blank string if user had no warning