I am pulling all of the information for solutions using cross referenced tables.
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
Which works fine and my results are as expected. However, I have another table which holds tasks for that solution, each task has a progress. I want to bring out how many tasks that solution has, I have tried:
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*) FROM t WHERE t.progress < 100 AS task)
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
But I am getting this error:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'AS task) FROM _user_solution s INNER JOIN _users u ON s.uid = u.uid' at line 3
Any ideas on how I can count all of the tasks that are incomplete to this solution would be much appreciated.
You need to move the AS task aliasing part outside the subquery; outside the closing bracket.
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*) FROM _solution_tasks WHERE progress < 100) AS task
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
you can try like below
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(*)
FROM another_table tt1
WHERE tt1.taskID=t.taskID --assume taskID is join key
and tt1.progress < 100
) AS task
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
I managed to figure out how to do it, I needed to put the progress in the WHERE clause at the bottom since that is what I am trying to query it all against and then I need to select COUNT(*)
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type, COUNT(*) as tasks
FROM _user_solution s
INNER JOIN _users u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks t
ON s.sid = t.assigned_for_solution
WHERE t.progress < 100
This is now giving me how many tasks are allocated to that solution. After doing abit of research, the first COUNT comes out as 0, like an array index starts at 0, so in this case, the solution row itself brings out 0 and then each task associated with the solution adds 1 giving me the correct multiple of tasks.
I've changed your query to this and it works:
SELECT
s.*, u.forname, u.surname, u.email, u.tel, p.type,
(SELECT COUNT(WRITE_AUTOINCREMENT_ID) AS task FROM t WHERE t.progress < 100)
FROM _user_solution AS s
INNER JOIN _users AS u
ON s.uid = u.uid
INNER JOIN _payment_plans p
ON p.pid = s.payment_plan_type
INNER JOIN _solution_tasks AS ttable
ON s.sid = ttable.assigned_for_solution
Related
EDIT the SQL version (mysql 5.7) I have does not support row_number() ... what alternative method can I used?
I researched an found out that using row_number() where is my query would I apply it... the columns I want to check are user_id racid and ios
SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id
Current Table after joining
user_id, racid, fname, lname, email, last_login, role_id, role_name, ios, group_name, ad_group, android
You can try below it will work for mysql 8+
select * from
(SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android,row_number() over(partition by ur.user_id,u.racid,i.device_token order by ur.user_id,
u.racid,i.device_token) as rn
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id
)X where rn<>1
OR Mysql below 8+ version you can try following
select * from
( SELECT
ur.user_id,
u.racid,
u.fname,
u.lname,
u.email,
u.last_login,
ur.role_id,
r.name AS role_name,
i.device_token AS ios,
dg.group_name,
dg.ad_group,
a.device_token AS android,
#row_number:=CASE
WHEN #user_id = ur.user_id and #racid = u.racid and #evicetoken = i.device_token THEN #row_number + 1
ELSE 1
END AS num,
#user_id :=ur.user_id, #racid = u.racid, #evicetoken = i.device_token
FROM
users AS u
LEFT OUTER JOIN
user_roles AS ur ON u.id = ur.user_id
LEFT OUTER JOIN
roles AS r ON ur.role_id = r.id
LEFT OUTER JOIN
ios_tokens AS i ON u.racid = i.racf_id
LEFT OUTER JOIN
android_tokens AS a ON u.racid = a.racf_id
LEFT OUTER JOIN
dashboard_groups AS dg ON dg.role_id = r.id,
(SELECT #user_id:=0,#racid=0,#evicetoken=0,#row_number:=0) as t
)X where num<>1
This is not about removing duplicate rows but if you need uniqueness from single table for multiple columns you can use unique index with multiple columns. If this is not you need kindly ignore this.
ALTER TABLE `users` ADD UNIQUE `unique_index`(`col1`, `col2`, `col3`);
How do I specify unique constraint for multiple columns in MySQL?
My current query:
select users.id as user_id, opportunities.id as op_id, opportunities.title, certificates.id as cert_id from opportunities
join opportunity_certificates on opportunities.id=opportunity_certificates.opportunity_id
join certificates on opportunity_certificates.certificate_id=certificates.id
join user_certificates on certificates.id=user_certificates.certificate_id
join users on user_certificates.user_id=users.id
where opportunity_certificates.is_required = 1 and
opportunities.id = 1
This produces the table on the picture below.
cert_id column can have values from 1 to 7, depends on the opportunities.id. In the table below, I want the query to return only the rows which have the same user_id but different cert_id, 1 and 2.
If the table had 3 different cert_id, I would want it to return only the rows which have same user_id but different cert_id, 1,2 and 3.
when the cert_id has only one value, query should return all the records with that one value in cert_id. Basically, it should show all users who have all required certificates.
The query has to be in the current format. I experimented with
group by users.id
having count(*) >
but I don't know how to make that comparison dynamic, relative to the count of distinctive values in the cert_id column.
Compare counts with a having condition.
select u.id as user_id --, o.id as op_id, o.title
from opportunities o
join opportunity_certificates oc on o.id=oc.opportunity_id
join certificates c on oc.certificate_id=c.id
join user_certificates uc on c.id=uc.certificate_id
join users u on uc.user_id=u.id
where oc.is_required = 1 and o.id = 1
group by u.id --,o.id,o.title
having count(distinct c.id)=(select count(distinct id) from certificates)
Useful?
with data as (
select users.id as user_id, o.title, c.id as cert_id
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
)
select user_id, min(title) as title, max(cert_id) as num_certs
from data
group by user_id
having count(cert_id) = (select max(cert_id) from data);
I'm assuming that cert_id values start and 1 and run sequentially. You could also use count(distinct ...) in the having clause but it guess it's debatable which ones expresses you intent more clearly.
If your version of MySQL doesn't support CTEs then you should be able to just drop that whole subquery into the having clause as well.
select u.id as user_id, min(o.title) as title, max(c.cert_id) as num_certs
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
group by u.id
having count(c.cert_id) = (
select max(c.cert_id)
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
);
Here's another one that might work if you have window functions available. (It might work with Laravel better?):
select *
from (
select users.id as user_id, o.title,
count(distinct c.id) over (partition by u.id) as user_certs,
max(c.id) over () as total_certs
from opportunities o
inner join opportunity_certificates oc on oc.opportunity_id = o.id
inner join certificates c on c.id = oc.certificate_id
inner join user_certificates uc on uc.certificate_id = c.id
inner join users u on u.id = uc.user_id
where oc.is_required = 1 and o.id = 1
) t
where user_certs = total_certs;
I have total 6 tables in which different info has been saved
Now i need a result in which get count from 5 tables and select all info from main table but if record does not exist than it must be need to return 0 instead of no row found that's the problem here
I have tried below query but didn't get success
SELECT
u.*,
COUNT(DISTINCT c.id) as comments,
COUNT(DISTINCT d.id) as dislikes,
COUNT(DISTINCT l.id) as likes,
COUNT(DISTINCT s.id) as shares,
COUNT(DISTINCT t.id) as tags
FROM
job_details as u
JOIN job_comments as c ON u.id = c.job_id
JOIN job_dislike as d ON u.id = d.job_id
JOIN job_like as l ON u.id = l.job_id
JOIN job_share as s ON u.id = s.job_id
JOIN job_tags as t ON u.id = t.job_id
WHERE
u.id = c.job_id AND
u.id = d.job_id AND
u.id = l.job_id AND
u.id = s.job_id AND
u.id = t.job_id
GROUP BY
u.id
This query is executed, but didn't get exact result.
I don't quite understand why.
I was hoping somebody here could help me out?
Thanks!
You probably didn't get the exact result because some tables may be missing values.
Although you can solve this problem with a LEFT JOIN, the safer solution is to pre-aggregate the data:
SELECT u.*, c.comments, d.dislikes, l.likes, s.shares, t.tags
FROM job_details as u LEFT JOIN
(select c.job_id, count(*) as comments from job_comments group by c.job_id
) c
ON u.id = c.job_id LEFT JOIN
(select d.job_id, count(*) as dislikes from job_dislike d group by d.job_id
) d
ON u.id = d.job_id LEFT JOIN
(select l.job_id, count(*) as likes from job_like l group by l.job_id
) l
ON u.id = l.job_id LEFT JOIN
(select s.job_id, count(*) as shares from job_share s group by s.job_id
) s
ON u.id = s.job_id LEFT JOIN
(select t.job_id, count(*) as tags from job_tags t group by t.job_id
) t
ON u.id = t.job_id;
Why is this better? Consider an id that has 5 comments, likes, dislikes, shares and tags. The JOIN approach produces an intermediate result with 5*5*5*5*5 = 3,125 intermediate rows. Things can really get out of hand for popular ids.
Use LEFT JOIN instead of JOIN. and you don't need WHERE clause since you have joined those tables. And, use IFNULL function to return 0 for null values. You need to modify you query like this :
SELECT u.id,
IFNULL(COUNT(DISTINCT c.id),0) as comments,
IFNULL(COUNT(DISTINCT d.id),0) as dislikes,
IFNULL(COUNT(DISTINCT l.id),0) as likes,
IFNULL(COUNT(DISTINCT s.id),0) as shares,
IFNULL(COUNT(DISTINCT t.id),0) as tags
FROM job_details as u
LEFT JOIN job_comments as c ON u.id = c.job_id
LEFT JOIN job_dislike as d ON u.id = d.job_id
LEFT JOIN job_like as l ON u.id = l.job_id
LEFT JOIN job_share as s ON u.id = s.job_id
LEFT JOIN job_tags as t ON u.id = t.job_id
GROUP BY u.id
I have a existing query where I am using joins (thanks RADAR) to get my data.
Working SQL
SELECT
IFNULL(f.field_full_name_value, 'No Value'), u.name, u.uid, n.title, n.nid, a.timestamp, d.field_video_duration_value AS duration
FROM
db_node_view_count a
join db_node n
ON a.nid = n.nid
JOIN db_field_data_field_video_duration d
ON n.nid = d.entity_id
JOIN db_users u
ON a.uid = u.uid
AND u.uid <> 1
LEFT JOIN db_field_data_field_full_name f
ON u.uid = f.entity_id
ORDER BY u.uid desc
What I want to do is that I want to extend the query to show roles of a db_users u. There is a table called db_roles, which contain all role names with a primary key rid. Then the second table is db_users_roles, which contains a matching uid (from db_users u) and rid to show which user selected which role.
So what I did was that under ON a.uid = u.uid, I added JOIN db_users_roles ur ON u.uid = ur.uid JOIN db_role r ON ur.rid = r.rid. It works fine but it shows duplicate rows. Any idea why it's happening?
SELECT
IFNULL(f.field_full_name_value, 'No Value'), r.name, u.name, u.uid, n.title, n.nid, a.timestamp, d.field_video_duration_value AS duration
FROM
db_node_view_count a
join db_node n
ON a.nid = n.nid
JOIN db_field_data_field_video_duration d
ON n.nid = d.entity_id
JOIN db_users u
ON a.uid = u.uid
LEFT JOIN db_users_roles ur
ON u.uid = ur.uid
LEFT JOIN db_role r
ON ur.rid = r.rid
AND u.uid <> 1
LEFT JOIN db_field_data_field_full_name f
ON u.uid = f.entity_id
ORDER BY u.uid desc
UPDATE
With help from Joe, here is a slight update:
SELECT
IFNULL(f.field_full_name_value, 'No Value'), GROUP_CONCAT(r.name), u.name, u.uid, n.title, n.nid, a.timestamp, d.field_video_duration_value AS duration
FROM
db_node_view_count a
join db_node n
ON a.nid = n.nid
JOIN db_field_data_field_video_duration d
ON n.nid = d.entity_id
JOIN db_users u
ON a.uid = u.uid
LEFT JOIN db_users_roles ur
ON u.uid = ur.uid
LEFT JOIN db_role r
ON ur.rid = r.rid
AND u.uid <> 1
LEFT JOIN db_field_data_field_full_name f
ON u.uid = f.entity_id
GROUP BY f.field_full_name_value
ORDER BY u.uid desc
Some users in your (Drupal) database may have more than one role. So where your original query had (simplified a bit) one row per node, the modified query will duplicate the rows for each role of the user.
You might want to modify the query to include
GROUP BY n.nid, u.uid
and change the SELECT field list to include GROUP_CONCAT(r.name) rather than r.name.
SELECT s.*,
u.username,
u.fullname,
c.title AS ctitle,
c.description AS cdescription,
sa.attention,
sp.popularity,
COUNT(DISTINCT f.id) AS favorites,
COUNT(DISTINCT st.id) AS stars,
COUNT(DISTINCT v.id) AS views
FROM shots s
INNER JOIN users u ON u.id = s.user_id
INNER JOIN categories c ON c.id = s.cat_id
LEFT OUTER JOIN(
SELECT shot_id, round(AVG(count),2) AS attention
FROM points
WHERE date > DATE_SUB(CURDATE(),INTERVAL 2 DAY)
GROUP BY shot_id
) sa ON sa.shot_id = s.id
LEFT OUTER JOIN(
SELECT shot_id, SUM(count) AS popularity
FROM points
GROUP BY shot_id
) sp ON sp.shot_id = s.id
LEFT OUTER JOIN favorites f ON f.shot_id = s.id
LEFT OUTER JOIN stars st ON st.shot_id = s.id
LEFT OUTER JOIN views v ON v.shot_id = s.id
**WHERE s.library = 1 AND sa.attention > 40
ORDER BY sa.attention DESC
LIMIT 0,50**
GROUP BY s.id
I can't use the sa.attention in a condition and for ordering. Why?
(I removed the marked part, and the query works!)
What do I have to change in my Query? And if you could give a explanation for it, that would be very nice!
You are negating your OUTER JOIN by putting that in your WHERE criteria. Move it to your JOIN and you'll get your NULL records back:
SELECT s.*,
u.username,
u.fullname,
c.title AS ctitle,
c.description AS cdescription,
sa.attention,
sp.popularity,
COUNT(DISTINCT f.id) AS favorites,
COUNT(DISTINCT st.id) AS stars,
COUNT(DISTINCT v.id) AS views
FROM shots s
INNER JOIN users u ON u.id = s.user_id
INNER JOIN categories c ON c.id = s.cat_id
LEFT OUTER JOIN(
SELECT shot_id, round(AVG(count),2) AS attention
FROM points
WHERE date > DATE_SUB(CURDATE(),INTERVAL 2 DAY)
GROUP BY shot_id
) sa ON sa.shot_id = s.id AND sa.attention > 40
LEFT OUTER JOIN(
SELECT shot_id, SUM(count) AS popularity
FROM points
GROUP BY shot_id
) sp ON sp.shot_id = s.id
LEFT OUTER JOIN favorites f ON f.shot_id = s.id
LEFT OUTER JOIN stars st ON st.shot_id = s.id
LEFT OUTER JOIN views v ON v.shot_id = s.id
WHERE s.library = 1
GROUP BY s.id
ORDER BY sa.attention DESC
LIMIT 0,50
A second note, GROUP BY cannot go at the end. I moved that to the correct spot as well.