count results different tables single query mysql php - php

I have the user id_user=5 who has posts in three different tables
questions (id_post | id_user ...) (7 posts)
marketplace (id_post | id_user ...) (9 posts)
jobs (id_post | id_user ...) (3 posts)
So I want to count, using a single query, the number of posts he has in each table
This is what I have so far...but it doesnt seems to work
(SELECT
COUNT(p.*) as count_questions
FROM $table_questions as p
WHERE p.id_user = :id_user1
)
UNION
(
SELECT
COUNT(m.*) as count_marketplace
FROM $table_marketplace as m
WHERE m.id_user = :id_user2
)
UNION
(SELECT
COUNT(e.*) as count_jobs
FROM $table_jobs as e
WHERE e.id_user = :id_user3
)
what am doing wrong?
I was expecting to retrieve in php like this
$count_questions = $result["count_questions"];
but it doesnt seems to work

SELECT COUNT(id_user) as counter
FROM $table_questions WHERE id_user = :id_user1
UNION
SELECT COUNT(id_user) as counter
FROM $table_marketplace WHERE id_user = :id_user2
UNION
SELECT COUNT(id_user) as counter
FROM $table_jobs WHERE id_user = :id_user3
Will return 3 rows each with the count, you have to give all the counts the same alias.
If you want to maybe identfy each result row specifically add another column as an identifier
SELECT 'Questions' as what, COUNT(id_user) as counter
FROM $table_questions WHERE id_user = :id_user1
UNION
SELECT 'Marketplace' as what, COUNT(id_user) as counter
FROM $table_marketplace WHERE id_user = :id_user2
UNION
SELECT 'Jobs' as what, COUNT(id_user) as counter
FROM $table_jobs WHERE id_user = :id_user3
Will give something like
what count
Questions 7
Marketplace 9
Jobs 3
And you can retrieve them as
$array = $stmt->fetch_all();
You will get an array like
Array
(
[Questions] => 7
[Marketplace] => 9
[Jobs] => 3
)

Related

Mysql : last five records if having same value

I searched a lot and tried many queries but not getting satisfied answer. So like to ask.
I am looking for last 5 records from mysql table if having same value otherwise not.
Something like if col_n is having same value x from last 5 records then count otherwise not. But I am not able to figure out how to write query for this ?
SELECT count(col_n)
from track if(last five col_n = 'ok')
WHERE col_a = 'value1' AND col_b = 'value2'
enter mysql table records
Please try this:
SELECT p.*
FROM
( SELECT *
FROM demo ORDER by id DESC
LIMIT 5
) AS p
JOIN
( SELECT COUNT(*) AS cnt
FROM
( SELECT 1
FROM demo
LIMIT 5
) AS tmp
) AS c
ON c.cnt = 5 WHERE p.name='x'

Suggestion SQL query

Basically what i am trying to do is to suggest people based on common interests.
I have a table of Users.
I have a table of Interested_People where UserID + InterestID is stored.
I have a table of Contactlist where people who are added with each other is stored.
What I want is to only output people who are not your friends.
I searched a lot in internet but couldn't find something like so.
Although I created a query but it is very slow. Now I Kindly request you guys if you can edit my query a bit and make it much more bandwidth & time efficient.
SELECT *
FROM users
WHERE id IN(SELECT userid
FROM interested_people
WHERE interested_in IN(SELECT interested_in
FROM interested_people
WHERE userid = [userid])
AND id NOT IN(SELECT user1 AS my_friends_userid
FROM contactlist f
WHERE f.user2 = [userid]
AND accepted = 1
UNION
SELECT user2 AS my_friends_userid
FROM contactlist f
WHERE f.user1 = [userid]
AND accepted = 1))
AND id != [userid]
ORDER BY Rand ()
LIMIT 0, 10;
This query actually does the job but it takes very long about 16 sec in my local machine. and that's not what I want. I want a fast and reliable one.
Thanks in advance!
Subqueries in WHERE clauses are often slow in MySQL; at least slower than comparable JOINs.
SELECT others.*
FROM interested_people AS userI
INNER JOIN interested_people AS othersI
ON userI.interestid = othersI.interestid
AND userI.userid <> othersI.userid
INNER JOIN users AS others ON othersI.user_id = others.userid
LEFT JOIN contactlist AS cl
ON userI.userid = cl.user1
AND others.userid = cl.user2
AND cl.accepted = 1
WHERE userI.userid = [userid]
AND cl.accepted IS NULL
ORDER BY RAND()
LIMIT 0, 10;
Note: intuition makes me wonder if contactlist might be better as a where subquery.
The AND cl.accepted IS NULL ends up processed after the JOINs, resulting in allowing only results that did NOT have a match in contactlist.
If you want to enhance things a bit further:
SELECT others.*, COUNT(1) AS interestsCount
...
GROUP BY others.userid
ORDER BY interestsCount DESC, RAND()
LIMIT 0,10;
This would give you a random selection of the people that share the most interests in common.
First, looking at your interested-in query and assuming the "userID"
you are testing with is = 1. Sounds like you are trying to get one level
away from those user 1 is also interested in...
SELECT userid FROM interested_people
WHERE interested_in IN
( SELECT interested_in FROM interested_people
WHERE userid = [userid] )
Sample Data for Interested_People
userID Interested_In
1 5
1 7
1 8
2 3
2 5
2 7
7 1
7 2
7 5
8 3
In this case, the innermost returns interested_in values of 5, 7, 8.
Then, getting all users who are interested in 5, 7 and 8 would return 2 and 7.
(but since both users 2 and 7 are interested in 5, the 2 ID would be returned TWICE
thus a possible duplicate join later on. I would do distinct. This same
result could be done with the following query which you could sample times with...
SELECT distinct ip2.userid
from
interested_people ip
join interested_people ip2
ON ip.interested_in = ip2.interested_in
where
userid = [parmUserID]
Now, you need to exclude from this list all your contacts already accepted.
You could then left-join TWO TIMES for the from/to contact and ensure NULL
indicating not one of the contacts... Then join again to user table to
get the user details.
SELECT
u.*
from
users u
JOIN
( SELECT distinct
ip2.userid
from
interested_people ip
join interested_people ip2
ON ip.interested_in = ip2.interested_in
left join contactList cl1
ON ip2.userid = cl1.user1
AND cl1.accepted = 1
left join contactList cl2
ON ip2.userid = cl2.user2
AND cl2.accepted = 1
where
ip.userid = [parmUserID]
AND NOT ip2.userID = [parmUserID] ) PreQuery
ON u.id = PreQuery.userID
order by
RAND()
limit
0, 10
I would have two indexes on your contactList table to optimize both left-joins... with user1 and user2 in primary position... Similarly for the interested_people table.
table index
contactList ( user1, accepted )
contactList ( user2, accepted )
interested_people ( userid, interested_in )
interested_people ( interested_in, userid )
I would expect your user table is already indexed on the ID as primary key.
I think this will give you the same results but perform a lot better:
SELECT * FROM Users u
INNER JOIN interested_people i
ON u.id = i.userid
WHERE NOT EXISTS
(SELECT * FROM contacts WHERE user1 = [userid] or user2 = [userid] and accepted=1)
AND id != [userid]
ORDER BY Rand()
LIMIT 0, 10
Skip the ORDER BY clause if that is at all reasonable. That will be the most expensive part
The select and join clauses give you the users who are interested in connecting and the WHERE NOT EXISTS is a performant way to exclude those contacts already listed.

update row without deleting previous values in mysql

One of my table has a field user_ids and the value of the field like 2,3
group_id| user_ids
--------|------------
1 | 2,3
--------|------------
2 | 5,8
I want to update the field without deleting the current value. For ex. If I need to add 5 for group_id id 1, then 2,3 should be like 2,3,5
I m using this query:
UPDATE users_group SET user_ids = CONCAT( SUBSTRING( user_ids, 1, CHAR_LENGTH( user_ids ) -1 ) , ',5' ) WHERE group_id =1
But it is deleting previous value with comma.
group_id| user_ids
--------|------------
1 | ,5
--------|------------
2 | 5,8
can anyone suggest the right way for this?
Can you not just concatenate it on, rather than trying to split it up first?
UPDATE users_group
SET user_ids = CONCAT_WS(',', user_ids, '5' )
WHERE group_id =1
But this does suggest a badly normalised database design. Generally a comma separated list should instead be stored as rows on another table (ie, one row per value in the list) as suggested by Mark Baker.
EDIT - If you want to only have a single copy of any id in each user_ids field, irrespective of how many times you try to insert it, and you want to be able to add multiple ids at once:-
UPDATE users_group a
INNER JOIN
(
SELECT 3 AS an_id
UNION
SELECT 4
) b
ON FIND_IN_SET(b.an_id, a.user_ids) = 0
SET a.user_ids = CONCAT_WS(',', a.user_ids, b.an_id )
WHERE a.group_id =1
EDIT again - if you have a table of users containing the ids then you can select the ids from that where the id is one of those you want to add.
Something like this.
UPDATE users_group a
INNER JOIN
(
SELECT id
FROM users
WHERE id IN (3, 4)
) b
ON FIND_IN_SET(b.id, a.user_ids) = 0
SET a.user_ids = CONCAT_WS(',', a.user_ids, b.id )
WHERE a.group_id =1
update table1 set name = concat(name, ', ', 5) WHERE group_id =1
Please try this query. It may be useful for you.
UPDATE users_group SET user_ids = CONCAT( user_ids , ',5' ) WHERE group_id =1
Try the below query:
UPDATE users_group
SET user_ids = CONCAT( user_ids , ',5' )
WHERE group_id =1

How to count records in MySQL and merge results in PHP

I have a table which stores clients like this:
id name
-- ----
1 John
2 Jane
...
I also have another table which stores links created by clients:
id client_id link created
-- --------- ---- -----------
1 1 ... 2015-02-01
2 1 ... 2015-02-26
3 1 ... 2015-03-01
4 2 ... 2015-03-01
5 2 ... 2015-03-02
6 2 ... 2015-03-02
I need to find how many links a client has created today, this month and during all the time. I also need their name in the result, so I'll be able to craete a HTML table to display the statistics. I thought I can code as less as possible like this:
$today = $this->db->query("SELECT COUNT(*) as today, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE DATE(l.created) = CURDATE() GROUP BY c.id");
$this_month = $this->db->query("SELECT COUNT(*) as this_month, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE YEAR(l.created) = YEAR(NOW()) AND MONTH(l.created) = MONTH(NOW()) GROUP BY c.id");
$yet = $this->db->query("SELECT COUNT(*) as yet, c.id as client_id, c.name FROM `links` l JOIN `clients` c ON l.client_id = c.id WHERE GROUP BY c.id");
And then merge them in PHP as I asked HERE before, like this:
$result = array_replace_recursive($today, $this_month, $yet);
So I'll be able to loop into the result and print my HTML table.
But there are logical problems here. Everything works fine, but the result in a month is a wrong number, forexample the whole created links of one person is 1 but it shows 4 in the monthly counter! I also tried to use RIGHT JOIN in SQL query to get all clients, so array_replace_recursive in PHP could work fine as I think it doesn't work properly at the moment, but no success and got wrong results again.
Can anyone show me a way to make the job done?
This query should do it for today
$query_today="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id AND created = '2015-03-02'
) AS alllinks
FROM clients"
adjust the WHERE clause in the subquery for months and all
$query_month="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id AND created like '2015-03%'
) AS alllinks
FROM clients"
$query_all="
SELECT name, id AS user_id, (
SELECT COUNT( * )
FROM links
WHERE client_id = user_id
) AS alllinks
FROM clients"

MySQL, check if result has value, if not take another [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a table structure like this:
Page_id || type || user_id
1 1 0
2 2 0
3 3 0
4 1 1
5 2 1
6 3 1
From this table I would like to get page_id 4,5 and 6.
But I can also have table data like this
Page_id || type || user_id
1 1 0
2 2 0
3 3 0
4 1 1
5 2 1
Then I would like to get page_id 4, 5 and 3.
So I have to get all the types, but with the priority user_id and if there is no record with user_id 1, then take the one with 0
Have tried a lot. I know I can sort it with PHP, but I hope there is a way with MySQL.
Regards Andreas
//////// ANSWER /////////
I got a lot of suggestions, and I haven't tried them all, so I can't tell it they where right or not. But I have accepted an answer, which worked for me.Thank to everybody.
SELECT a.Type, a.Page_ID
FROM table a
INNER JOIN
(SELECT Type, MAX(User_ID) AS User_ID
FROM table
GROUP BY Type ) b
ON a.Type = b.Type AND a.User_ID = b.User_ID
You can execute a SELECT query as follow
SELECT Page_id
FROM table
WHERE user_id != 0
This SQL Fiddle demonstrates the below query:
SELECT DISTINCT
(
SELECT s1.Page_id
FROM myTable AS s1
WHERE m.type = s1.type
ORDER BY s1.Page_id
LIMIT 1
) AS PageID, type,
(
SELECT s2.user_id
FROM myTable AS s2
WHERE m.type = s2.type
ORDER BY s2.Page_id
LIMIT 1
) AS User
FROM myTable AS m
The results are the records where Page_id is 1, 2, and 4. As you can see in both of the sub queries I am ordering by Page_id to make sure the data is pulled from the same record and the first Page_id for that occurrence of the type is selected.
To return only one record unique to a couple columns, you'll want to use the GROUP BY statement. Then for any other column outside of the group by columns, you need to pick an aggregate function so it knows how to summarize the value if it finds multiple records in that group. In this case you want non-zero, so max() would work
SELECT type, max(user_id) as user_id
FROM table
GROUP BY type
how about that?
select page_id,type from (
select page_id,type, user_id from mytable
group by page_id,type, user_id having user_id=max(user_id)
) as x where user_id=1
Will there ever be multiple rows for a page where user_id is not zero? Because if not (if at most you only have one row per page where user_id = 1) then this will work:
SELECT ifNull(t1.page_id,t2.page_id) as page_id, t1.type,
CASE WHEN t2.page_id IS NULL THEN t1.user_id ELSE t2.user_id END as user_id
#start with all rows (including duplicates)
FROM myTable t1
#look for a user_id > 0 for this type
LEFT OUTER JOIN myTable t2 ON t1.type = t2.type AND t2.user_id > 0
WHERE t2.page_id IS NULL # if no record with user_id > 0 found, then no need to filter
# if a record with user_id > 0 was found, then filer out the user_id = 0 record
OR (t2.page_id IS NOT NULL AND t1.user_id > 0)
See in SQLFiddle: http://sqlfiddle.com/#!2/ba877/5

Categories