cI'm seeking some help with my left join with a limit.
What i'm trying to do is to loop through my users and check in another table if there's problems connected to the user.
But currently I'm getting all kinds of weird results and it does not LIMIT the result for each user and it also lists column status_link_missing = 0 even though i have told the sub query to only list status_link_missing = 1
So I'm stuck for now, help is much appreciated!
SELECT
a.user_id AS settings_userid
, a.contact_interval
, b.user_id
, b.notify_user
, b.status_host_down
, b.status_link_missing
, b.status_relnofollow
FROM `link_exchange_settings` a
LEFT JOIN link_exchange_links b
ON b.id
= ( SELECT c.id
FROM link_exchange_links AS c
WHERE
b.user_id = a.user_id
AND c.notify_user = 1
AND c.status_link_missing = 1
LIMIT 1
)
WHERE a.allow_contact = 1
LIMIT 10
Edit
I switched SELECT b.id to c.id now and LIMIT works but now it only works for the first user
Try this change (no reference to b in the subquery):
SELECT
a.user_id AS settings_userid
, a.contact_interval
, b.user_id
, b.notify_user
, b.status_host_down
, b.status_link_missing
, b.status_relnofollow
FROM `link_exchange_settings` a
LEFT JOIN link_exchange_links b
ON b.id
= ( SELECT c.id -- changed
FROM link_exchange_links AS c
WHERE
c.user_id = a.user_id -- changed
AND c.notify_user = 1
AND c.status_link_missing = 1
-- ORDER BY c.something -- optional, recommended addition
LIMIT 1
)
WHERE a.allow_contact = 1
-- ORDER BY a.something_else -- optional, recommended addition
LIMIT 10 ;
It's also good to have ORDER BY when you use LIMIT. Unless you want indeterminate results.
You are using "c.status_link_missing = 1" in sub-query but if you will use it in WHERE clause with "AND" you will get your desired results.
In fact you have to decide and use appropriate condition in WHERE clause of main query instead of LEFT JOIN sub-query.
Related
Imagine that we have a database with a logs table and types table. I want to do a query where I figure out if UserX has entries for certain types of logs. Let's say that UserX has logged type_1 and type_2, but not type_3. I want to write a simple query to see if this is true or false.
At first I tried something like:
SELECT * FROM logs AS l
INNER JOIN types AS t
ON t.id = l.type_id
WHERE t.name = "type_1"
AND t.name = "type_2"
AND t.name != "type_3";
But I quickly realised that it was not possible to do it like this, since t.name cannot have multiple values. I have tried a bunch of different approaches now, but cannot seem to find the one right for me. I'm sure the solution is fairly simple, I just don't see it at the moment.
Hope someone can point me in the right direction.
I have made a simple test database in this fiddle, to use for testing and example: https://www.db-fiddle.com/f/nA6iKgCcJwKnXKsxaNvsLt/0
One option with conditional aggregation.
SELECT l.userID
FROM logs AS l
JOIN types AS t ON t.id = l.type_id
GROUP BY l.userID
HAVING COUNT(DISTINCT CASE WHEN t.name IN ('type_1','type_2') THEN t.name END) = 2
AND COUNT(DISTINCT CASE WHEN t.name = 'type_3' THEN t.name END) = 0
You can do it like Vamsi, but if you prefer an easier to understand SQL then you can do it like this:
SELECT * FROM logs AS l
INNER JOIN types AS t
ON t.id = l.type_id
WHERE true
AND EXISTS (SELECT 1 FROM logs ll WHERE l.user_id = ll.user_id AND type_id = 1)
AND EXISTS (SELECT 1 FROM logs ll WHERE l.user_id = ll.user_id AND type_id = 2)
AND NOT EXISTS (SELECT 1 FROM logs ll WHERE l.user_id = ll.user_id AND type_id = 3)
I do not recommend using count(distinct) for this purpose. It can be expensive. I would simply do:
SELECT l.userId
FROM logs l INNER JOIN
types t
ON t.id = l.type_id
WHERE t.name IN ('type_1', 'type_2', 'type_3')
GROUP BY l.userId
HAVING SUM(t.name = 'type_1') > 0 AND -- at least one
SUM(t.name = 'type_2') > 0 AND -- at least one
SUM(t.name = 'type_3') = 0 ; -- none
I have tow tables, first table related to forms and second table relate to adviser.each adviser can add comment for a form.
I tried select some column of two tables. It was works i have last subject of second table (adviser table ) in my result .but i need first subject of second table(adviser table ) .
#DQL
SELECT
f.name,
f.title,
f.conditionResultFinal,
f.conditionResult,
f.formCode,
f.dateInsert,
f.id,
(a.idFormRequestProject),
a.subject as subjectAdvisor
FROM AdminBundle:FormRequestProject f
JOIN AdminBundle:Advisor a
WHERE a.idFormRequestProject = f.id
AND (f.conditionResultFinal = 0 OR f.conditionResult = 0)
AND f.displayStatus = 1
GROUP BY f.id
ORDER by a.id,f.id DESC
Finally i solve this problem .i deleted GROUP By .and add new where ...
SELECT f.name,f.title,f.conditionResultFinal,
f.conditionResult ,
f.formCode,f.dateInsert ,
f.id,(a.idFormRequestProject),
a.subject as subjectAdvisor
FROM AdminBundle:FormRequestProject f
Left JOIN AdminBundle:Advisor a WHERE f.id = a.idFormRequestProject AND a.id =
(SELECT Max (aa.id) FROM AdminBundle:Advisor aa WHERE a.idFormRequestProject =
aa.idFormRequestProject ORDER by aa.id ASC ) AND
(f.conditionResultFinal = 0 OR f.conditionResult = 0 ) AND f.displayStatus =1
ORDER by f.id DESC
I have query below:
SELECT t.t_id
, t.usr_idx
, t.t_is_for
, t.tg_ids
, t.created_time
, t.allow_reply
, u.usr_name
, u.usr_avatar
, u.show_profile
, IF(u.usr_timeline != '',CONCAT('https://s3.amazonaws.com/tuurnts3thumbnail/',u.usr_timeline),'') as usr_timeline
, u.node_userid
, t.t_time
FROM tuu_tuurnt t
JOIN tuu_user u
ON t.usr_idx = u.usr_idx
AND u.usr_state = 1
LEFT
JOIN tuu_post p
ON t.t_id = p.t_id
AND p.usr_idx = 44756
LEFT
JOIN tuu_friend f
ON f.frd_my_idx = 44756
AND f.frd_your_idx = t.usr_idx
LEFT
JOIN tuu_friend fl
ON fl.frd_your_idx = 44756
AND fl.frd_my_idx = t.usr_idx
WHERE t.status = 0
AND NOT EXISTS ( SELECT b.tuu_b_by_usr_idx
FROM tuu_blocked as b
WHERE b.tuu_b_usr_idx = 44756
AND t.usr_idx = b.tuu_b_by_usr_idx
)
GROUP
BY t.t_id
ORDER
BY t.t_time DESC
, t.t_id DESC
LIMIT 0,30;
It takes almost 7-8 second to give result but when I remove order by t.t_time and t.t_id then it runs within 1 sec max.
Is there anything I am doing wrong?
Without an index, MySQL must begin with the first row and then read through the entire table to find the relevant rows. The larger the table, the more this costs. See How MySQL Uses Indexes for details. See also this topic about using indexes and aliases together.
I'm trying to execute a SQL SELECT query to get all the stores within a city and also have a field to inform if the store is within working hours or not.
This is the SQL I have so far:
$day = date('w');
$hour = date('H:i:s');
SELECT a.id, a.rating, a.name, a.image, b.cityName
(
SELECT 1 FROM tbStore a, workingHour b
WHERE a.id = b.id_store
AND b.weekDay = '$day'
AND b.hourOpen <= '$hour'
AND b.hourClose >= '$hour')
) as 'open'
FROM tbStore a, tbCity b
WHERE b.url = '$url'
AND a.id_city = b.id
ORDER BY open
The way I'm checking this value is as a boolean, so the 'open' field needs to be 0 (closed) or 1 (open).
It's kind of working... But the problem is, if just 1 store is within working hours, all of the others will be 'open' as well, instead of just that specific store.
I also saw some sql statements where people use CASE instead of another select, so any other type of code can be used, as long as the final result is correct.
You're redefining the tbStore a and losing the restriction by $url. You probably just need to change:
SELECT 1 FROM tbStore a, workingHour b
To:
SELECT 1 FROM workingHour b
I have just rewrite you query using explict join way
SELECT
a.id
, a.rating
, a.name
, a.image
, b.cityName
, when( c.id_store is not null then 1 else 0 end) as open
FROM tbStore a
inner join tbCity b on a.id_city = b.id
LEFT join workingHour c on a.id = c.id_store
WHERE b.url = '$url'
AND c.weekDay = '$day'
AND c.hourOpen <= '$hour'
AND c.hourClose >= '$hour'
ORDER BY open
In relation to the answer I accepted for this post, SQL Group By and Limit issue, I need to figure out how to create that query using SQLAlchemy. For reference, the query I need to run is:
SELECT t.id, t.creation_time, c.id, c.creation_time
FROM (SELECT id, creation_time
FROM thread
ORDER BY creation_time DESC
LIMIT 5
) t
LEFT OUTER JOIN comment c ON c.thread_id = t.id
WHERE 3 >= (SELECT COUNT(1)
FROM comment c2
WHERE c.thread_id = c2.thread_id
AND c.creation_time <= c2.creation_time
)
I have the first half of the query, but I am struggling with the syntax for the WHERE clause and how to combine it with the JOIN. Any one have any suggestions?
Thanks!
EDIT: First attempt seems to mess up around the .filter() call:
c = aliased(Comment)
c2 = aliased(Comment)
subq = db.session.query(Thread.id).filter_by(topic_id=122098).order_by(Thread.creation_time.desc()).limit(2).offset(2).subquery('t')
subq2 = db.session.query(func.count(1).label("count")).filter(c.id==c2.id).subquery('z')
q = db.session.query(subq.c.id, c.id).outerjoin(c, c.thread_id==subq.c.id).filter(3 >= subq2.c.count)
this generates the following SQL:
SELECT t.id AS t_id, comment_1.id AS comment_1_id
FROM (SELECT count(1) AS count
FROM comment AS comment_1, comment AS comment_2
WHERE comment_1.id = comment_2.id) AS z, (SELECT thread.id AS id
FROM thread
WHERE thread.topic_id = :topic_id ORDER BY thread.creation_time DESC
LIMIT 2 OFFSET 2) AS t LEFT OUTER JOIN comment AS comment_1 ON comment_1.thread_id = t.id
WHERE z.count <= 3
Notice the sub-query ordering is incorrect, and subq2 somehow is selecting from comment twice. Manually fixing that gives the right results, I am just unsure of how to get SQLAlchemy to get it right.
Try this:
c = db.aliased(Comment, name='c')
c2 = db.aliased(Comment, name='c2')
sq = (db.session
.query(Thread.id, Thread.creation_time)
.order_by(Thread.creation_time.desc())
.limit(5)
).subquery(name='t')
sq2 = (
db.session.query(db.func.count(1))
.select_from(c2)
.filter(c.thread_id == c2.thread_id)
.filter(c.creation_time <= c2.creation_time)
.correlate(c)
.as_scalar()
)
q = (db.session
.query(
sq.c.id, sq.c.creation_time,
c.id, c.creation_time,
)
.outerjoin(c, c.thread_id == sq.c.id)
.filter(3 >= sq2)
)