I'm trying to find a query to resolve my issue:
i have something like this on my database:
i need a query that selects all users that have role 5 but if for some reason they have any other role it should skip them
SELECT user_id FROM user_table WHERE roleid = 5 AND (roleid != 3 OR roleid != 1)
That still returns user 64
I think you are looking for a not exists clause:
select *
from t
where roleid = 5 and
not exists (select 1
from t t2
where t2.user_id = t.user_id and t2.roleid <> 5
);
Alternatively, if you are just looking for such users, then you can use group by and having:
select user_id
from t
group by user_id
having min(roleid) = max(roleid) and min(roleid) = 5;
(If roleid could be NULL, the logic would need to take this into account.)
Related
I can't find the answer to the current question with my versions of SQL so hopefully someone can help me out.
I am using MySQL with SQLPro as the client or I can use PostgreSQL pgAdmin 4.
scenario I am trying to update a null value with the previous not null value.
here is my table:
primary_id name address id
1 bob 123 main 100
2 jane 123 main NULL
3 mike 217 2nd 200
4 jeff 217 2nd NULL
How can I populate the null values with the not null values so that the address/ID grouping remain constant down my columns?
thanks!!!
If you want to update the table, this will work in Postgres:
update t
set id = (select t2.id
from t t2
where t2.address = t.address and t2.id is not null
fetch first 1 row only
)
where id is null;
In MySQL, this will work:
update t join
(select address, max(id) as max_id
from t
group by address
) tt
on t.address = tt.address
set t.id = tt.max_id
where t.id is null;
You can try updating the table with itself. I inserted your table into a users table I created in postgres:
UPDATE users
SET
id = _users.id
FROM
(
SELECT DISTINCT
address,
id
FROM users
WHERE id IS NOT NULL
GROUP BY
address,
id
) _users
WHERE
_users.address = users.address
AND users.id IS NULL;
So the idea is that I grab all all the non-null address and id groups (assuming address is always paired with the same id. I call this _users.
Match _users.address with your original users.address. Make sure that you are only updating the NULL users.id.
I have three tables:
user: id, name
keyword: id, name
userkeyword: id, user_id, keyword_id
I want to execute query in following way:
Display those users whose keyword/s are matched with the login user's
keywords. In the order of maximum number of keyword matched user
should display first
e.g : If userA having 4 matched keywords, userB having 8, userC having 1, userD having 6 then the result should be in the order of,
userB
userD
userA
userC
For that I have done with this query (assume login user's id is 1):
select *
from user
where id IN (
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc)
AND id != 1
Here the result is getting perfect but the order is not correct. I have merged two queries in following manner"
select *
from user
where id IN (?)
AND id!=1
+
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc
Second query returns user_id in correct order but when I merged both queries, order was changed (wrong).
Hope I have mentioned my query properly with enough detail.
A subquery returns an unordered set, so the order by in a subquery only matters for its limit clause, if there is any. Any database other than MySQL would give an error message for a purely decorative sort order.
There's no way to sort on a column that only exists in the where clause. You'd have to rewrite the query. One option is to replace your in conditions with joins:
select uk2.name
from userkeywords uk1
join userkeywords uk2
on uk1.keyword_id = uk2.keyword_id
and uk1.user_id <> uk2.user_id
join user u2
on u2.id = uk2.user_id
where uk1.user_id = 1
group by
uk2.name
order by
count(*) desc
This should do it.
select uk.user_id, u.name
from userkeywords uk
left join user u on u.id = uk.user_id
where uk.keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by uk.user_id
order by count(uk.keyword_id) desc) AND uk.user_id != 1
Also, JOIN provides better performance.
I would use an inner join to select the correct rows:
SELECT *
FROM user
INNER JOIN (
SELECT * FROM userkeyword
WHERE keyword_id IN (
SELECT keyword_id
FROM userkeyword
WHERE user_id=1
)
) uk
ON user.id = uk.user_id
GROUP BY u.id
ORDER BY count(*) DESC;
I was wondering what is better in MySQL. I have a SELECT query that exclude every entry associated to a banned userID.
Currently I have a subquery clause in the WHERE statement that goes like
AND (SELECT COUNT(*)
FROM TheBlackListTable
WHERE userID = userList.ID
AND blackListedID = :userID2 ) = 0
Which will accept every userID not present in the TheBlackListTable
Would it be faster to retrieve first all Banned ID in a previous request and replace the previous clause by
AND creatorID NOT IN listOfBannedID
LEFT JOIN / IS NULL and NOT IN are fastest:
SELECT *
FROM mytable
WHERE id NOT IN
(
SELECT userId
FROM blacklist
WHERE blackListedID = :userID2
)
or
SELECT m.*
FROM mytable m
LEFT JOIN
blacklist b
ON b.userId = m.id
AND b.blackListedID = :userID2
WHERE b.userId IS NULL
NOT EXISTS yields the same plan but due to implementation flaws is marginally less efficient:
SELECT *
FROM mytable
WHERE NOT EXISTS
(
SELECT NULL
FROM blacklist b
WHERE b.userId = m.id
AND b.blacklistedId = :userID2
)
All these queries stop on the first match in blacklist (hence performing a semi-join)
The COUNT(*) solution is the least efficient, since MySQL will calculate the actual COUNT(*) rather than stopping on the first match.
However, if you have a UNIQUE index on (userId, blacklistedId), this is not much of problem as there cannot be more than one match anyway.
Use EXISTS clause to check for user not in blacklist.
Sample Query
Select * from userList
where not exists( Select 1 from TheBlackListTable where userID = userList.ID)
IN clause is used when there is fixed values or low count of values.
My query is:
SELECT * FROM table WHERE id IN (1,2,3,4);
I use it for usergroups and a user can be in more than one group. but it seems that when a record has multiple id like 1 and 3, mySQL does not return that row.
Is there any way to get that row too?
Your query translates to
SELECT * FROM table WHERE id='1' or id='2' or id='3' or id='4';
It will only return the results that match it.
One way of solving it avoiding the complexity would be, chaning the datatype to SET.
Then you could use, FIND_IN_SET
SELECT * FROM table WHERE FIND_IN_SET('1', id);
You have wrong database design and you should take a time to read something about database normalization (wikipedia / stackoverflow).
I assume your table looks somewhat like this
TABLE
group_id
user_ids
name
1
1,4,6
group1
2
4,5,1
group2
so in your table of user groups, each row represents one group and in user_ids column you have set of user ids assigned to that group.
Normalized version of this table would look like this
GROUP
id
name
1
group1
2
group2
GROUP_USER_ASSIGNMENT
group_id
user_id
1
1
1
4
1
6
2
4
Then you can easily select all users with assigned group, or all users in group, or all groups of user, or whatever you can think of. Also, your sql query will work:
/* Your query to select assignments */
SELECT * FROM `group_user_assignment` WHERE user_id IN (1,2,3,4);
/* Select only some users */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE user_id IN (1,4);
/* Select all groups of user */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE t1.`user_id` = 1;
/* Select all users of group */
SELECT * FROM `group_user_assignment` t1
JOIN `group` t2 ON t2.id = t1.group_id
WHERE t1.`group_id` = 1;
/* Count number of groups user is in */
SELECT COUNT(*) AS `groups_count` FROM `group_user_assignment` WHERE `user_id` = 1;
/* Count number of users in group */
SELECT COUNT(*) AS `users_count` FROM `group_user_assignment` WHERE `group_id` = 1;
This way it will be also easier to update database, when you would like to add new assignment, you just simply insert new row in group_user_assignment, when you want to remove assignment you just delete row in group_user_assignment.
In your database design, to update assignments, you would have to get your assignment set from database, process it and update and then write back to database.
Here is sqlFiddle to play with.
you must have record in table or array record in database.
example:
SELECT * FROM tabel_record
WHERE table_record.fieldName IN (SELECT fieldName FROM table_reference);
I've got a table called transaction
Transaction:
User_Id: int
Transaction_Type: int
Amount: int
How would I query all users that do not have transaction type 1.
SELECT * FROM Transaction WHERE Transaction_Type <> 1 Group By User_Id
seems to return all users & their transaction types that are not = to 1. I need all users that are missing / have no record of type 1.
This can be done with an IN() subquery
SELECT DISTINCT User_Id FROM Transaction
WHERE User_Id NOT IN (SELECT DISTINCT User_Id FROM Transaction WHERE Transaction_Type = 1)
Or with a NOT EXISTS
SELECT
DISTINCT User_Id
FROM Transaction t
WHERE
NOT EXISTS (SELECT User_Id FROM Transaction tn WHERE Transaction_Type = 1)
AND t.User_Id = tn.User_Id
There's probably a more elegant way of doing this, but this should work:
SELECT * FROM Transaction WHERE User_Id NOT IN (SELECT User_Id FROM Transaction WHERE Transaction_Type = 1)
SELECT *
FROM ( SELECT DISTINCT User_Id FROM Transaction ) AS User
LEFT JOIN Transaction ON Transaction.User_Id = User.id
AND Transaction.Transaction_Id != 1
WHERE Transaction.Transaction_Id IS NULL
GROUP BY User.id
SELECT DISTINCT User_Id
FROM Transaction
WHERE Transaction_Id <> 1
GROUP BY User_Id
This gets each User_Id which has at least one transaction which is not of type 1. If you also want the ones with no transactions, add OR Transaction_Id IS NULL to the WHERE statement.
For example
SELECT DISTINCT User_Id
FROM [Transaction]
EXCEPT
SELECT User_Id
FROM [Transaction]
WHERE Transaction_Id = 1
That's if you don't have a separate table for users. If you do, then use an outer join.
I would suggest not using keywords (like Transaction) as table/column names
I'd do this with a JOIN. Assuming a Users table:
SELECT u.*
FROM Users u
LEFT JOIN Transaction t
ON t.User_ID = u.User_ID
AND t.Transaction_Type = 1
WHERE t.User_ID IS NULL
This method avoids the subquery and DISTINCT.