Mysql select not duplicated values with condition - mysql

I'm looking for faster way to run this kind of statment:
SELECT *
FROM `aukcje_przedmioty`
WHERE (
(
opis NOT
IN (
SELECT opis
FROM aukcje_przedmioty
WHERE ( aktywne =1 AND user_id =6 )
)
)
AND aktywne =0
AND user_id =6
)
table aukcje_przedmioty

you can try something like
SELECT a.*
FROM `aukcje_przedmioty` a
JOIN
(
SELECT opis,user_id
FROM aukcje_przedmioty
GROUP BY opis,user_id
HAVING max(aktywne) = 0
) x
ON
x.user_id = a.user_id and
x.opis = a.opis
WHERE user_id = 6
http://sqlfiddle.com/#!2/16774/6
Use explain on your setup to see what would work best for you.

Related

MySql Query with UNION and SORT

Actually i am trying to create a conversation interface like FB(Messages) and for that a sql query is used to fetch all the persons whom with user is talked already.
I need the id of the user from whom he had talked in descending order,
Like if A has chatted with B and C. Then B AND C will be result of that query and B will come first because A chatted with B recently.
My 'messages' table structure is :
http://www.softnuke.com/me/files/DB.png
This is the FB example:
http://www.softnuke.com/me/files/msg.png
This is my incorrect query which needs to be fixed:
SELECT DISTINCT(`mates`)FROM(
SELECT `time` AS `time`,`from_id` AS `mates`
FROM `messages` AS T WHERE (`from_id`=$uid OR `to_id`=$uid)
UNION
SELECT `time` AS `time`,`to_id` AS `mates`
FROM `messages` AS T WHERE (`from_id`=$uid OR `to_id`=$uid)
) AS T
WHERE `mates`!='$uid'
ORDER BY `time`
$uid will give me the variable of the user I want to fetch List(Here its A).
You seem to be getting the main person and the person they were talking to, irrespective of which one is the main person. Also not quite sure how MySQL will work out the time to order things by when you are using DISTINCT which will remove some of the records with their times.
You could get the max time and order by that:-
SELECT `mates`, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`,`from_id` AS `mates`
FROM `messages` AS T WHERE `to_id`=$uid
UNION
SELECT `time` AS `time`,`to_id` AS `mates`
FROM `messages` AS T WHERE `from_id`=$uid
) AS T
GROUP BY `mates`
ORDER BY LatestConv
To get the status of that latest message:-
SELECT a.mates, a.LatestConv, IFNULL(b.Status, c.Status)
FROM
(
SELECT mates, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`, from_id AS mates
FROM messages AS T
WHERE to_id = $uid
UNION
SELECT `time` AS `time`, to_id AS mates
FROM messages AS T
WHERE from_id = $uid
) AS T
GROUP BY `mates`
) a
LEFT OUTER JOIN messages b
ON a.mates = b.from_id AND a.LatestConv = b.`time` AND b.to_id = $uid
LEFT OUTER JOIN messages c
ON a.mates = c.to_id AND a.LatestConv = c.`time` AND c.from_id = $uid
ORDER BY LatestConv
Note that this might get a touch confused if there are multiple messages to the same person which all share the same latest time. If this is likely it could be coped with as follows:-
SELECT a.mates, a.LatestConv, MAX(IFNULL(b.Status, c.Status))
FROM
(
SELECT mates, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`, from_id AS mates
FROM messages AS T
WHERE to_id = $uid
UNION
SELECT `time` AS `time`, to_id AS mates
FROM messages AS T
WHERE from_id = $uid
) AS T
GROUP BY `mates`
) a
LEFT OUTER JOIN messages b
ON a.mates = b.from_id AND a.LatestConv = b.`time` AND b.to_id = $uid
LEFT OUTER JOIN messages c
ON a.mates = c.to_id AND a.LatestConv = c.`time` AND c.from_id = $uid
GROUP BY a.mates, a.LatestConv
ORDER BY LatestConv

update query with subselects from the same table

I'm trying to create a query to update the rank field of all the records in the table, based on values from the same table.
I managed to get a working SELECT query that calculates the rank, but I'm having a hard time converting it to an UPDATE. This is the query:
SELECT
((views_count + comments_count) * (172800 / elapsed)) AS rank
FROM (
SELECT
p.views_count,
(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(p.createdAt)) AS elapsed,
(SELECT COUNT(*) FROM `comments` AS c WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m
How can I implant it in an UPDATE query, to update each record's rank value?
Thanks! :)
EDIT:
My DB structure:
[Photo]
id
user_id
views_count
rank
createdAt
[Comment]
id
photo_id
content
Just a guess, but something like this should work:
UPDATE `photos`
FROM (
SELECT id
, (views_count + comments_count) * (172800 / elapsed) AS rank
FROM (
SELECT p.id
, p.views_count
, ( UNIX_TIMESTAMP(NOW())
- UNIX_TIMESTAMP(p.createdAt)) AS elapsed
, (SELECT COUNT(*)
FROM `comments` AS c
WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m
) AS z
SET rank=z.rank
WHERE `photos`.id=z.id
You should write your new ranks to a temporary table and use that to update the original table. try
CREATE TEMPORARY TABLE tmp_tbl AS (
SELECT ((views_count + comments_count) * (172800 / elapsed)) AS rank, m.id
FROM (SELECT
p.views_count,
(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(p.createdAt)) AS elapsed,
(SELECT COUNT(*) FROM `comments` AS c WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m);
and then
UPDATE photos, tmp_tbl SET photos.rank = tmp_tbl.rank WHERE photos.id=tmp_tbl.id;
and finally
DROP TABLE tmp_tbl;
See this simliar stackoverflow question

how do I change my complex mysql query into mysql view

I'm a nubie in mysql queries, and I would like to ask, whether if there's someone who can help me to solve my problem. I have this complex(for me) sql. and I want to change it into a view.
SELECT
username,
user_id,
sum(result_points) AS count_points,
count(result_points) AS activity_done,
(
(
SELECT count(*) FROM `activity` WHERE periode_id = ''
) +
(
SELECT
IFNULL(sum(acs.result_points), 0)
FROM
user_activity ua
WHERE
periode_id = ''
AND ua.user_id = user_activity.user_id
AND ua.result_points IS NOT NULL
)
) AS total
FROM
user_activity
LEFT JOIN users ON users.id = user_activity.user_id
WHERE
periode_id = ''
and user_id > 0
GROUP BY user_id
ORDER BY total DESC
is there a way, to take out the "where" statement,so that i still can change it to view?
If you query is correct, create view like
Create View data as
SELECT
username,
user_id,
sum(result_points) AS count_points,
count(result_points) AS activity_done,
(
(
SELECT count(*) FROM `activity` WHERE periode_id = ''
) +
(
SELECT
IFNULL(sum(acs.result_points), 0)
FROM
user_activity ua
WHERE
periode_id = ''
AND ua.user_id = user_activity.user_id
AND ua.result_points IS NOT NULL
)
) AS total
FROM
user_activity
LEFT JOIN users ON users.id = user_activity.user_id
WHERE
periode_id = ''
and user_id > 0
GROUP BY user_id
ORDER BY total DESC
Remove where clause from view and add where clause in view, like
select * from data where user_id > 0

Mysql query optimization

HI im running socialengine3 and need optimization on the a custom Mutual friends query.
Its currently taking 15 seconds to execute
Friends table
friend_id
friend_user_id1
friend_user_id2
friend_status
friend_type
users
user_id
Edited
I have converted in into exists and still its now executing in 20 seconds.
below is the updated query.
SELECT friendlist.friend_user_id2, se_users.username, se_users.id, se_users.image, se_users.name, se_users.surname, count( * ) AS mutral_friends
FROM `se_friends` friendlist
INNER JOIN `users` se_users ON friendlist.friend_user_id2 = `se_users`.id
WHERE EXISTS (
SELECT se.friend_user_id2
FROM se_friends se
WHERE se.friend_user_id1 = '105012'
AND se.friend_status = '1'
AND se.friend_user_id2 = friendlist.friend_user_id1
) AND NOT EXISTS (
SELECT se1.friend_user_id2
FROM `se_friends` se1
WHERE se1.friend_user_id1 = '105012'
AND friendlist.friend_user_id2 = se1.friend_user_id2
)
AND NOT (
friendlist.friend_user_id2 = '105012'
)
AND friendlist.friend_status = '1'
GROUP BY friendlist.friend_user_id2, se_users.username, se_users.id, se_users.image, se_users.name, se_users.surname
ORDER BY mutral_friends DESC
LIMIT 0 , 20
Orignal query
SELECT DISTINCT `se_friends`.friend_user_id2, se_users.username, se_users.id, se_users.image, se_users.name, se_users.surname, count(*) as mutral_friends
FROM `se_friends`
INNER JOIN `users` se_users` ON `se_friends`.friend_user_id2=`se_users`.id
WHERE
(se_friends.friend_user_id1 <> '30355' or se_friends.friend_user_id2 <> '30355') AND
se_friends.friend_user_id1 IN
(SELECT se_friends.friend_user_id2
FROM `se_friends`
WHERE se_friends.friend_user_id1='".$user_id."' AND se_friends.friend_status='1')
AND `se_friends`.friend_user_id2 NOT IN
(SELECT se_friends.friend_user_id2
FROM `se_friends`
WHERE se_friends.friend_user_id1='".$user_id."'
)
AND NOT(se_friends.friend_user_id2='".$user_id."') AND se_friends.friend_status='1'
GROUP BY `se_friends`.friend_user_id2, se_users.username, se_users.id, se_users.image, se_users.name, se_users.surname
ORDER BY mutral_friends DESC
LIMIT 0, 20
IN is very expensive operation.
try to replace it with EXISTS. eg
select * from table where user_id in (select user_id from users where active='A')
and
select * from table t where exists (select user_id from users u where t.user_id = u.user_id and u.active='A')
if it won't be helpful, it's better to look at execution plan

What's wrong on this query?

I'm selecting total count of villages, total count of population from my tables to build statistics. However, there is something wrong. It returns me everything (530 pop (there are 530 pop in total), (106 villages (there are 106 users in total)) in first row, next rows are NULLs
SELECT s1_users.id userid, (
SELECT count( s1_vdata.wref )
FROM s1_vdata, s1_users
WHERE s1_vdata.owner = userid
)totalvillages, (
SELECT SUM( s1_vdata.pop )
FROM s1_users, s1_vdata
WHERE s1_vdata.owner = userid
)pop
FROM s1_users
WHERE s1_users.dp >=0
ORDER BY s1_users.dp DESC
Try removing s1_users from inner SELECTS
You're already using INNER JOINs. Whan you list tables separated with comma, it is a shortcut for INNER JOIN.
Now, the most obvious answer is that your subqueries using aggregating functions (COUNT and SUM) are missing a GROUP BY clauses.
SELECT s1_users.id userid, (
SELECT count( s1_vdata.wref )
FROM s1_vdata, s1_users
WHERE s1_vdata.owner = userid
GROUP BY s1_vdata.owner
)totalvillages, (
SELECT SUM( s1_vdata.pop )
FROM s1_users, s1_vdata
WHERE s1_vdata.owner = userid
GROUP BY s1_vdata.owner
)pop
FROM s1_users
WHERE s1_users.dp >=0
ORDER BY s1_users.dp DESC
However, using subqeries in column list is really inefficient. It casues subqueries to be run once for each row in outer query.
Try like this instead
SELECT
s1_users.id AS userid,
COUNT(s1_vdata.wref) AS totalvillages,
SUM(s1.vdata.pop) AS pop
FROM
s1_users, s1_vdata --I'm cheating here! There's hidden INNER JOIN in this line ;P
WHERE
s1_users.dp >= 0
AND s1_users.id = s1_vdata.owner
GROUP BY
s1_users.id
ORDER BY
s1_users.dp DESC
SELECT s1_users.id AS userid,
(
SELECT COUNT(*)
FROM s1_vdata
WHERE s1_vdata.owner = userid
) AS totalvillages,
(
SELECT SUM(pop)
FROM s1_vdata
WHERE s1_vdata.owner = userid
) AS pop
FROM s1_users
WHERE dp >= 0
ORDER BY
dp DESC
Note that this is less efficient than this query:
SELECT s1_users.id AS user_id, COUNT(s1_vdata.owner), SUM(s1_vdata.pop)
FROM s1_users
LEFT JOIN
s1_vdata
ON s1_vdata.owner = s1_users.id
GROUP BY
s1_users.id
ORDER BY
dp DESC
since the aggregation needs to be done twice in the former.
SELECT userid,totalvillages,pop from
(
SELECT s1_users.id as userid, count( s1_vdata.wref ) as totalvillages
FROM s1_vdata, s1_users
WHERE s1_vdata.owner = userid
GROUP BY s1_users.id) tabl1 INNER JOIN
(
SELECT s1_users.id as userid, SUM( s1_vdata.pop ) as pop
FROM s1_users, s1_vdata
WHERE s1_vdata.owner = userid
GROUP BY s1_users.id) tabl2 on tabl1.userid = tabl2.userid