How would I write a query that would select the name of a person (a column in the row) given that they have enough rows to meet all conditions?
For example, I have a database set up like so:
name permission_id
Bob 1
Bob 2
Jerry 3
Jerry 1
Jose 2
Billy 1
Billy 2
How would I only select the people that have permission id 1 and 2? In other words, I would like a query that checks every person by name to see if they have all the permissions requested.
In this example if I was to check for all users to who have permission 1 and 2 I should get Bob and Billy as a return value.
Here is my current query:
$this->db->select('center_user_permissions.id, center_users.first_name, center_users.last_name');
$this->db->from('center_user_permissions');
$this->db->where_in('permission_id', $permission_ids);
$this->db->join('center_users', 'center_users.center_id = center_user_permissions.center_id');
Currently this query returns anybody who has either permission id 1 or 2. I need it to be 1 AND 2. But I know I can't simply make two wheres because one particular row can't have both permission ids, but the query must check all rows for the specified ids.
I believe I would need a SELECT statement inside of my where? Can anybody tell me if I'm thinking correctly? Thanks.
You can use a in clause an an having for check that the user has both the permission
select name
from center_user_permissions
where permissions_id in (1,2)
group by name
having count(*) = 2
I'm not sure how to build this query in CodeIgniter, but you could INNER JOIN for each permission ID you want the user to have:
SELECT center_users.center_id, center_users.first_name, center_users.last_name
FROM center_users
INNER JOIN center_user_permissions AS p1 ON p1.center_id=center_users.center_id AND p1.permission_id=1
INNER JOIN center_user_permissions AS p2 ON p2.center_id=center_users.center_id AND p2.permission_id=2
You could check for more permissions by adding a INNER JOIN for each additional permission you wanted to require.
MySQL's GROUP BY and HAVING
Not user what kind of DB interface you're using in $this->db, but it may make things a little tricky. If I start with a raw SQL query:
SELECT
center_user_permissions.id,
center_users.first_name,
center_users.last_name
FROM center_user_permissions
LEFT JOIN center_users
ON center_users.center_id = center_user_permissions.center_id
WHERE center_user_permissions.permission_id in (1,2)
Group by name, where count of permission_id is > 1
This will group rows by first_name (so you'll only get one row for each unique name). Doing do allows you to run aggregate functions (SUM(), MAX(), COUNT()) against the rows that were "grouped" into a single row.
SELECT
center_user_permissions.id,
center_users.first_name,
center_users.last_name
FROM center_user_permissions
LEFT JOIN center_users
ON center_users.center_id = center_user_permissions.center_id
GROUP BY center_users.first_name
WHERE center_user_permissions.permission_id in (1,2)
HAVING COUNT(center_user_permissions.permission_id)>1
select distinct(name),.. as name from 'center_user_permissions',center_users where
center_users.center_id = center_user_permissions.center_id and permissions_id in (1,2)
substitute .. with your other fields and put in distinct the value that you want to be unique
Related
I have two tables:
employees:
id, CMS_user_id, practice_group_id, ...
and
users:
id, level, ...
I want to select all employees where practice_group_id is 2 but only if the respective user has a level of 1 according to the users table. I researched and I have a feeling it has something to do with the UNION keyword eventually, but I can't quite figure it out.
In "human language", the query would be like this:
"select all from employees where practice_group_id is 2 and then check the CMS_user_id from the employee and check in the table users whether the respective user with the id that equals CMS_user_id has a level of 1"
A JOIN will match the corresponding rows between two tables. Then, filtering can be done using WHERE.
For example:
select e.*
from employees e
join users u on u.id = e.CMS_user_id
where e.practice_group = 2 and u.level = 1
I have two tables:
access(name, id, check, key)
events(name, key, event_name)
I am trying to print some things from these tables into a php/html table with these columns:
name, key, event_name, access count
My trouble being I would like each event to display the "count" of access rows that have the same key.
Event table example:
name key event_name
test 1 first
joe 2 second
And the access table...
name id check key
test 123 yes 1
test 1235 yes 1
joe 175 yes 2
joe 852 yes 2
test 5843 yes 1
test 123455 yes 1
The resulting table I am hoping to look like this:
name key event_name access count
test 1 first 4
joe 2 second 2
Does anybody know how to do this? I've gotten to this but it obviously doesn't work because the key isn't given to the inner select query...
select event_name, name, key,
(SELECT COUNT(key) FROM access WHERE key=key AND name=name)
from event;
Thank you to anyone who takes a look and might have any ideas! I've been staring at this and w3schools for hours
At present your subquery will return a count of all rows as it is not correlated to the main query, so both occurrences of key in key=key will refer to the same column and the expression will always be true (likewise for name). To correlate the subquery, add table references:
select event_name, name, key,
(SELECT COUNT(key) FROM access a WHERE a.key=e.key AND a.name=e.name) AS `access count`
from event e
You can also get the same results with a join and aggregattion:
select e.name, e.key, e.event_name, count(*) access_count
from event e
left join access a on a.key = e.key and a.name = e.name
group by e.name, e.key, e.event_name
I have 2 tables A & B
Table A
ID NAME
1 John
2 Jack
3 Mark
Table B
ID phone UserID
s1 4586 1
s2 6996 1
s3 9654 2
they are one to many relation (John has 2 phone on Table 2)
my sql query
$sql = 'SELECT *
FROM
A
Join
B
ON
B.USER_ID = A.ID
WHERE
A.ID=:ID';
my PHP
foreach($vars['GROUPS'] as $row) {
<tr><th>Name</th><td><?=$row['Name']?></td></tr>
<tr><th>phone</th><td><?=$row['phone']?></td></tr>
}
I want to show the phones number for this user John name then show all his details from table 2 . as it now loop for me
You have 2 options:
Use group_concat() function in sql to concatenate all telephone numbers a user has into a single string and use pretty much the same loop in php as you use now.
select a.id, a.name, group_concat(b.phone) as phone
from a inner join b on a.id=b.user_id
group by a.id, a.name
Leave your current sql query intact, but change the php loop displaying the table. In this case only print out a name with all the corresponding phone numbers after looping through all the records returned from the query. Just concatenate all phone numbers in the loop.
I do not know if I understand your question right. From your query you get two rows for the user John, one is "1-John-s1-4586-1" and the other is "1-John-s2-6996-1", right? And you want just one row for that user containing both his phone numbers? Then you could use GROUP_CONCAT:
SELECT A.*, GROUP_CONCAT(b.phone) FROM
A INNER JOIN B ON A.id = B.UserID
WHERE A.ID=:ID
GROUP BY A.id
See the MySQL documentation for more options of the GROUP_CONCAT function: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
For example, you could use ordering or a custom separator.
In PHP you could use explode() if you want to iterate over the phone numbers.
I have two MySql Tables as follows:
resource
-----------------------------------------------
id name group owner_id
-----------------------------------------------
1 MyResource1 hs 11
2 MyResource2 ms 24
3 MyResource3 ps 11
...
resource_access
-----------------------------------------------
id resource_id user_id
-----------------------------------------------
1 1 12
2 2 24
3 2 11
4 3 15
...
Now, the first table is a list of resources, of course, and their respective owners in the owner_id column. The second table is the result of "sharing" this resource with another user. The table resource_access may contain records with a user_id that is equivalent to the owner_id in a row of the resource_access as a result of messy cleanup from an owner exchange.
I simply want to get the id, name, and group of any resource that a user has access to, whether they are the owner or it has been shared with them. Here is my MySQL query for an example user (24):
SELECT resource.id, resource.name, resource.group
FROM `resource`
INNER JOIN resource_access ON (
resource.owner_id='24'
OR (
resource_access.user_id='24' AND
resource_access.resource_id=resource.id
)
)
Right now, it returns the id, name, and group for resource number 2 multiple times (like twelve). Is there a possible cause for this? I have tried LEFT and RIGHT joins and am getting the same result. There are many records in the resource table, but none with the id of 2. There are no duplicate rows in resource_access sharing the resource with the same user twice.
Thanks in advance.
Use:
SELECT DISTINCT resource.id, resource.name, resource.group
to remove duplicates.
The way an inner join conceptually works is that it produces a full cross-product between the two tables. This cross-product contains a row for each pair of rows in the input tables. Then it keeps the rows that match all the ON and WHERE conditions, and returns this as the result set. If there are multiple matching rows between the two tables, you'll get multiple rows in the result set.
If you were selecting columns from both tables, you would see that they're not actually the same row. They just have the same data from the resource table, but different data from the resource_access table. But you're not showing those latter columns in your result. Using DISTINCT merges all these rows in the result.
Because you are only selecting from the resource table, I would suggest putting the conditions in the where clause rather than using an explicit join:
SELECT r.id, r.name, r.group
FROM `resource` r
WHERE r.owner_id='24' or
EXISTS (select 1
from resource_access ra
where ra.resource_id = r.id and
ra.user_id = '24'
);
With this logic, the "join" cannot product duplicates.
Select the ownership of resources then union it to resources with access.
Resulting user_id column that is different from your WHERE RA.user_id value just means that resource was shared to them instead of them owning the resource. Hope this helps.
SELECT resource.name,resource.group,resource.owner_id AS user_id
FROM resource
WHERE resource.owner_id = '11'
UNION
SELECT R.name,R.group,R.owner_id AS user_id
FROM resource_access RA
LEFT JOIN resource R
ON (R.id=RA.resource_id)
WHERE RA.user_id = '11';
Scenario
I have three elements in this problem. One is an array of ids in this format: (1,3,5,6,8). That array is a list of id of users I want to display. The second element is table that contains user information something simple like: id name surname email. The third element is a second table that contains users configuration. There are two parameters in that last table, one is lid, and the other is usraction (among others, but the important are those two). lid represent a permission type and usraction the value, if the user wants his data to be public there will be a row on that table where lid=3 and usraction="accepted", also I register the datetime of the action every time the user changes this permission, so each time he change it a new row is added, and in order to retrieve the actual state of the permission i have to retrieve the last row for the user an check the value of usraction like this:
SELECT * FROM legallog WHERE uid = '.$user['id'].' AND lid = 3 ORDER BY ABS(`registration` - NOW()) LIMIT 1
Then in php:
if($queryresult && $queryresult[0]['usraction']=='accepted') //display data
The problem
In the scenario id described how im getting the actual state of the permission set by one user at the time, the problem now is I want to sort of clean an array of ids in one or two sql calls. Lets say I want to print the user information of 4 users, one function gives me the ids in this format: (2,6,8,1), but those users may not want to display their information, using the query I showed before I can make a call to the sql server for each user and then generate a new array, if the users who authorize are 1 and 8 the result array will be (8,1).
The think is whit an array of 100 users I will make 100 calls, and I dont want this, is there a way to solve this in one or two querys?
A query such as this gets you the information you want:
select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
If you only want "accepted" values, then make this a subquery:
select t.*
from (select u.*,
(select usraction from configuration c where c.userid = u.userid and c.lid = 3 order by datetime limit 1
) as lastLid3Action
from users u
where u.userid in (1,3,5,6,8)
) t
where LastLid3Action = 'Accepted'
As I understand you have two tables in the first table, where the user information is stored; and the second table, where the user permission is stored. And you want to get information from the first table using permission from the second table, then you need this query:
SELECT a.*
FROM first-table-name AS a
RIGHT JOIN second-table-name AS b a.uid = b.lid
WHERE uid in (1,3,5,6,8) AND usraction='accepted'
ORDER BY ABS)
LIMIT 1
You question is somewhat vague, but if you are asking how to select a number of records when you have a list of ids, the answer is:
select column, list, goes, here from tablename
where id in (1,5,8,12,413);
That will get you the values of the columns you list for just the records that match your array of ids.