i have a search query that i need to modify and adapt into a custom profile system we have, that system use the following table:
profile_key | profile_value | user_id
1 | test1 | 10
2 | test2 | 10
3 | ["test3","test4"] | 10
i need to add to the where clause something that would match all the rows (depending of what the user defined in the search form) to get the user_id, something like:
select user_id from table where (profile_key = 1 && profile_value regexp 'test1') && (profile_key = 3 && profile_value regexp 'test4')
i need to get all the user_id IF it matched all the defined profile_key and the regexp.
any idea how i can accomplish this?
Regards.
The simplest way would be to use EXISTS:
SELECT user_id
FROM users
WHERE EXISTS (SELECT 1 FROM profiles WHERE profile_key = 1
AND profile_value regexp 'test1' AND profiles.user_id = users.user_id)
AND EXISTS (SELECT 1 FROM profiles WHERE profile_key = 3
AND profile_value regexp 'test4' AND profiles.user_id = users.user_id)
You could also accomplish this with an INNER JOIN, once for each row you want to match:
SELECT user_id
FROM users
INNER JOIN profiles p1 ON users.user_id = p1.user_id
INNER JOIN profiles p2 ON users.user_id = p2.user_id
WHERE p1.profile_key = 1 AND p1.profile_value regexp 'test1'
AND p2.profile_key = 3 AND p2.profile_value regexp 'test4'
You're saying that profile_key should be 1 and 3. This is impossible.
You need to use an OR, not AND.
SELECT user_id
FROM table
WHERE ( profile_key = 1 && profile_value REGEXP 'test1' ) OR (
profile_key = 3 && profile_value REGEXP 'test4' )
What about using an 'IN', something like this
select user_id
from table
where (profile_key = 1 && 'test1' IN profile_value)
&& (profile_key = 3 && 'test4' IN profile_value )
Related
I'm having a problem which i cannot manage to fix.
I've been looking at some other posts but most of them were either to complex for me to understand/use or do not deal with the same problem.
First the tables:
Person
id | amt
=============
1 | 5
2 | 26
3 | 3
Goal
id | idPerson | goals
===========================
1 | 1 | "AAA"
2 | 1 | "AAA"
4 | 1 | "DDD"
5 | 2 | "CCC"
6 | 2 | "BBB"
7 | 3 | "AAA"
What I want:
I need all Person ids where the Person does not have the goal "AAA".
Currently a Person can only have between 1 and 3 goals in the Table Goal.
My Select:
SELECT Person.id, Person.amt
FROM Person
WHERE amt < 10
AND Person.id IN
(
SELECT Goal.idPerson
FROM Goal
WHERE Person.id = Goal.idPerson
AND Goal.goals != "AAA"
)
If possible could someone explain me why my SQL is not working and what i have to do different so it works? With an explanation i could avoid the same problem in the future. :)
Thank you.
EDIT:
I did not thought that this would make a problem but when i filter not only for 'AAA' but also for 'BBB' then it I will get results with 'AAA', 'BBB' and even some with both.
How the Where is now:
AND Person.id NOT IN
(
SELECT Goal.idPerson
FROM Goal
WHERE Person.id = Goal.idPerson
AND Goal.goals = 'AAA'
AND Goal.goals = 'BBB'
)
You probably looking for NOT EXISTS instead like
SELECT Person.id, Person.amt
FROM Person
WHERE amt < 10
AND NOT EXISTS
(
SELECT 1
FROM Goal
WHERE idperson = person.id AND goals = "AAA"
)
You don't need it to be correlated and you want to use NOT IN instead:
select Person.id,
Person.amt
from Person
where amt < 10
and id not in (
select idPerson
from Goal
where goals = 'AAA'
)
You need to use NOT IN rather than IN, e.g.:
SELECT *
FROM Person
WHERE amt < 10
AND Person.id NOT IN (
SELECT idPerson FROM Goal WHERE goals = 'AAA'
);
Also change this:
AND Goal.goals != "AAA"
to
AND Goal.goals != 'AAA'
Your subselect filters all rows that do not match "AAA". That includes "DDD". You can use
SELECT * FROM Person p
WHERE NOT EXISTS (SELECT g.id FROM Goal g WHERE g.goals="AAA" AND g.idPerson=p.id)
Table Structure :
Registration :
uuid | name | total
Rate :
uuid | type | rate
Registration_Rate :
registration | rate
Initial Request is :
select * from registration r
join registration_rate rr on rr.registration = r.uuid
join rate rt on rt.uuid = rr.rate
group by r.name, rt.type
My SQL result from two table (registration & rate ) is :
uuid | name | rate | type
1 | AAA | 15 | U
2 | BBB | 20 | U
3 | CCC | 300 | F
4 | AAA | 250 | F
I would like to have something like this (if a rate's type 'F' exists then display instead)
uuid | name | rate | type
2 | BBB | 20 | U
3 | CCC | 300 | F
4 | AAA | 250 | F
Thanks
Edited :
I have tried another solution which works
select uuid, name, rate, (case rt.type when 2 then 2 else 1 end ) as type
from registration r
join registration_rate rr on rr.registration = r.uuid
join rate rt on rt.uuid = rr.rate
group by r.name, rt.type
If it's an F row return it. Or, use NOT EXISTS to verify no other row with same name has an F.
select t1.*
from tablename t1
where type = 'F'
or not exists (select * from tablename t2
where t2.name = t1.name
and t2.type = 'F')
Alternative solution:
select t1.*
from tablename t1
join (select name, min(type) type
from tablename
group by name) t2
ON t1.name = t2.name and t1.type = t2.type
Try this (I suggest main idea)
SELECT t.uuid,
t.name,
IFNULL(MAX(t.F_type), MAX(t.not_F_type)) AS "type",
IFNULL(MAX(t.F_rate), MAX(t.not_F_rate)) AS "rate"
FROM
(
SELECT r.uuid,
r.name,
CASE rt.type WHEN 'F' THEN rt.type END AS F_type,
CASE WHEN rt.type <> 'F' THEN rt.type END AS not_F_type,
CASE rt.type WHEN 'F' THEN rt.rate END AS F_rate,
CASE WHEN rt.type <> 'F' THEN rt.rate END AS not_F_rate
FROM registration AS r
JOIN registration_rate AS rr ON rr.registration = r.uuid
JOIN rate AS rt ON rt.uuid = rr.rate
) as t
GROUP BY t.uuid, t.name;
So, you need to split appropriate columns ("rate", "type") according to your rule (if a rate's type 'F' exists then display instead of others) into two new separate columns using case statement: the first column contains value for F type and the second one contains value for others types. I did it for "type" and "rate" columns. Then I glued together these columns (and records) using group by, aggregation functions and IFNULL statement (you can use others statement here: case, IF, etc).
As I understand the question, this is what you need.
I have three tables as following:
USERS TABLE
id_user| name |
---------------
1 | ...
2 | ...
SERVICES TABLE
id_service | name |
-------------------
1 | ...
2 | ...
3 | ...
USER_SERVICES TABLE (n-m)
id_user | id_service
--------------------
1 | 1
1 | 2
2 | 1
And I need to do a SELECT starting from "SELECT * FROM users" and then, getting the users by services. Ex. I need to get every user with services = 1 and services = 2 (and maybe he has other more services, but 1 and 2 for sure).
I did the following:
SELECT *
FROM `users`
INNER JOIN user_services ON users.id_user = user_services.id_user
WHERE id_service=1 AND id_service=2
But this, of course dont works since there is not a single record matching service = 1 and service = 2.
What can I do?
Add an extra join for the other service you want to check:-
SELECT *
FROM `users`
INNER JOIN user_services us1 ON users.id_user = us1.id_user AND us1.id_service=1
INNER JOIN user_services us2 ON users.id_user = us2.id_user AND us2.id_service=2
select t.*,
(select count(*) from user_services where id_user = t.id_user) how_much
from users t;
Is this what you want???
It shows the data of the users and how much services are in the services table. Other possibility is this:
select t.*,
(case when (select count(*)
from user_services where id_user = 1) > 0
then 'service1'
else 'null'
end) has_service_1
from users t;
The problem with this select is that you have to repeat this case...end as much times as id_services you have, so it doesn't make sense if the number of services is increasing over time. On the contrary, if it is a somewhat fixed number, and it is not a big number, this could be a solution.
I want to select all users from my database with emails ending #gmail.com which are not already in the group with the groupID 4.
The problem is my user_to_group table looks like this:
userID | groupID
--------------------
1 | 5
1 | 4
1 | 3
2 | 3
2 | 6
Users with the groupID 4 are excluded, but because they are also in other groups, they will be selected anyway. In this example I just need the user with the userID 2.
Is it possible to exclude users which are in group 4 regardless of their other groups?
SELECT * FROM wcf13_user user_table
RIGHT JOIN wcf13_user_to_group ON (wcf13_user_to_group.userID = user_table.userID && groupID != 4 )
WHERE user_table.email LIKE "%#gmail.com"
Yes, you can do it with an EXISTS subquery:
SELECT *
FROM wcf13_user user_table u
WHERE user_table.email LIKE "%#gmail.com" -- Has a gmail account
AND NOT EXISTS ( -- Is not a member of group #4
SELECT *
FROM wcf13_user_to_group g
WHERE u.userID=g.userID AND groupID = 4
)
This is a good place to use the not exists clause:
SELECT ut.*
FROM wcf13_user ut
WHERE not exists (select 1
from wcf13_user_to_group utg
where utg.userID = ut.userID and utggroupID = 4
) and
ut.email LIKE '%#gmail.com';
Please consider the following table structure and data:
+--------------------+-------------+
| venue_name | listed_by |
+--------------------+-------------+
| My Venue Name | 1 |
| Another Venue | 2 |
| My Venue Name | 5 |
+--------------------+-------------+
I am currently using MySQL's GROUP BY function to select only unique venue names. However, this only returns the first occurance of My Venue Name, but I would like to return it based on a condition (in this case where the listed_by field has a value > 2.
Essentially here's some pseudo-code of what I'd like to achieve:
Select all records
Group by name
if grouped, return the occurance with the higher value in listed_by
Is there an SQL statement that will allow this functionality?
Edit: I should have mentioned that there are other fields involved in the query, and the listed_by field needs to be used elsewhere in the query, too. Here is the original query that we're using:
SELECT l1.field_value AS venue_name,
base.ID AS listing_id,
base.user_ID AS user_id,
IF(base.user_ID > 1, 'b', 'a') AS flag,
COUNT(img.ID) AS img_num
FROM ( listingsDBElements l1, listingsDB base )
LEFT JOIN listingsImages img ON (base.ID = img.listing_id AND base.user_ID = img.user_id and img.active = 'yes')
WHERE l1.field_name = 'venue_name'
AND l1.field_value LIKE '%name%'
AND base.ID = l1.listing_id
AND base.user_ID = l1.user_id
AND base.ID = l1.listing_id
AND base.user_ID = l1.user_id
AND base.active = 'yes'
GROUP BY base.Title ORDER BY flag desc,img_num desc
As long as you didn't mention other fields - here is the simplest solution:
SELECT venue_name,
MAX(listed_by)
FROM tblname
WHERE listed_by > 2
GROUP BY venue_name
With other fields it could look like (assuming there is no duplicates in venue_name + listed_by pairs):
SELECT *
FROM tblname t1
INNER JOIN (SELECT venue_name,
MAX(listed_by) max_listed_by
FROM tblname
WHERE listed_by > 2
GROUP BY venue_name) t2 ON t1.venue_name = t2.venue_name
AND t1.listed_by = t2.max_listed_by