PL/SQL SELECT on two tables - mysql

I've got two tables. One of these contains userData and the other one contains userGroups linked to users which are in a Group.
Means like a user can be in 0 or more Groups.
I'm trying to get this columns with a query used like this:
SELECT distinct(a.userID), a.userName, Count(b.userID_FID)
FORM userData a,
userGroup b
WHERE a.userID = b.userID_FID
But somehow the Count part returning me a wrong number.

SELECT max(a.userName), Count(distinct b.userID_FID)
FROM userData a
JOIN userGroup b
ON a.userID = b.userID_FID
GROUP BY a.userID
My suggestion is do not use many tables with from

This will get you the number of groups each user is in.
To build the test scenario, use this:
create table #groups
(userID_FID int
,groups int
);
create table #user
(userID int);
insert into #groups values (1, 5);
insert into #groups values (1, 2);
insert into #groups values (1, 3);
insert into #groups values (1, 4);
insert into #groups values (2, 3);
insert into #groups values (2, 4);
insert into #groups values (3, 1);
insert into #groups values (3, 5);
insert into #user values (1);
insert into #user values (2);
insert into #user values (3);
select * from #groups;
select * from #user;
This piece is the query you want, according to the test scenario above:
select userid, count(*) as NumberOfGroups
from #groups g
, #user u
where g.userID_FID = u.userID
group by userID;

Related

MySQL find ids for which there is no existing row

I have three tables :
1. Person (person_id, name) : (1, "Test1"), (2, "Test2"), (3, "Test3")
2. Role (role_id, description) : (1, "Admin"), (2, "Designer"), (3, "Developer") ..
3. PersonRoles (person_id, role_id) : (1 , 1), (1, 2), (2, 3), (2, 1), (3, 1)
Is it possible in MySQL with a query to get the ids of the people for which there`s no row with exact role in the PersonRoles table. For Example if I want to check for "Designer" role the query should return ids: 2 and 3
Here is your solution:
select person_id from Person
where person_id not in
(select person_id from Role r
inner join PersonRoles pr on pr.role_id=r.role_id
where r.description='Designer')
You could use the not exists operator:
SELECT *
FROM Person p
WHERE NOT EXISTS (SELECT *
FROM Role r
JOIN PersonRoles pr ON r.role_id = pr.role_id
WHERE r.description = 'Designer' AND
pr.person_id = p.person_id)

MySQL query returning detailed group_contact information (with join)?

I have query which return me color of the owner and his pet's numbers. How to return instead of
[Red][1,2]
someting more detailed like
[Red][Rufus, Bali]
It's name of pet with join on id of the pet. Is possibile to make another Columns on every pet name? (without using few selects of courst)
CREATE TABLE pet (id INT, name VARCHAR(20));
insert into pet values (1,"Rufus");
insert into pet values (2,"Bali");
insert into pet values (3,"Lolo");
CREATE TABLE own (id INT, own_name VARCHAR(20), own_color VARCHAR(20));
insert into own values (1,"Me", "Red");
insert into own values (2,"Other owners" ,"Green");
CREATE TABLE pet_owner (id INT, id_pet INT, id_own INT);
insert into pet_owner values (1, 1, 1);
insert into pet_owner values (2, 2, 1);
insert into pet_owner values (3, 3, 2);
DROP procedure if exists `pet`;
DELIMITER $$
CREATE procedure `pet`()
BEGIN
set #param = 1;
select o.own_color as color,
(select group_concat(id_pet) from pet_owner po where po.id_own = #param) as pets
from own o
where o.id = #param;
END$$
call pet;
select o.own_color as color,
(select group_concat(p.name) from pet_owner po join pet p ON p.id = po.id_pet where po.id_own = #param) as pets
Try the following--the keys are the aggregate GROUP_CONCAT function and the GROUP BY clause:
select o.own_color as color, group_concat(p.name) as pet_names
from own o
inner join pet_owner po on o.id = po.id_own
inner join pet p on po.id_pet = p.id
group by o.id;

Select data from other table during insert?

I am inserting data into a database that looks like this:
(1, 'blue'), (2,'large'), (3, 'round')
The numbers there correspond to ID's from another table. that looks like: id | value
When inserting this data I want to insert the actual value that the number corresponds to, not the id.
Is there any query to do this? or do I need match the values before sending it to the database?
While I know it won't work, I am hoping there is something like:
insert into table2 (table1.value[id=1], 'blue'), (table1.value[id=2],'large'), (table1.value[id=3], 'round') join table1
I imagine I could use:
insert into table2
((select value from table1 where id=1), 'blue'),
((select value from table1 where id=2),'large'),
((select value from table1 where id=3), 'round')
But with say, 40 different attributes that would make 41 queries!
First virtually make up a table with the values you want to insert (id,value), then join the derived table to table1 and INSERT the result into table2.
insert into table2
select t.value, madeup.other
from (select 1 id, 'blue' other union all
select 2, 'large' union all
select 3, 'round') madeup
join table1 t on t.id = madeup.id;
You could use a temporary table to map id to value. I don't really speak MySQL, but something like this:
create table #mapping (id int, description varchar)
insert into #mapping values (1, 'blue')
insert into #mapping values (2, 'large')
insert into #mapping values (3, 'round')
insert into table2
select table1.value, #mapping.description
from #mapping
join table1 on table1.id = #mapping.id
drop table #mapping

Help with INSERT INTO..SELECT

I'm inserting a large number of rows into Table_A. Table_A includes a B_ID column which points to Table_B.B_ID.
Table B has just two columns: Table_B.B_ID (the primary key) and Table_B.Name.
I know the value for every Table_A field I'm inserting except B_ID. I only know the corresponding Table_B.Name. So how can I insert multiple rows into Table_A?
Here's a pseudocode version of what I want to do:
REPLACE INTO Table_A (Table_A.A_ID, Table_A.Field, Table_A.B_ID) VALUES
(1, 'foo', [SELECT B_ID FROM Table_B WHERE Table_B.Name = 'A'),
(2, 'bar', [SELECT B_ID FROM Table_B WHERE Table_B.Name = 'B'),...etc
I've had to do things like this when deploying scripts to a production environment where Ids differed in environments. Otherwise it's probably easier to type out the ID's
REPLACE INTO table_a (table_a.a_id, table_a.field, table_a.b_id)
SELECT 1, 'foo', b_id, FROM table_b WHERE name = 'A'
UNION ALL SELECT 2, 'bar', b_id, FROM table_b WHERE name = 'B'
If the values:
(1, 'foo', 'A'),
(2, 'bar', 'B'),
come from a (SELECT ...)
you can use this:
INSERT INTO Table_A
( A_ID, Fld, B_ID)
SELECT Data.A_ID
, Data.Field
, Table_B.B_ID
FROM (SELECT ...) As Data
JOIN Table_B
ON Table_B.Name = Data.Name
If not, you can insert them into a temporary table and then use the above, replacing (SELECT ...) with TemporaryTable.
CREATE TABLE HelpTable
( A_ID int
, Fld varchar(200)
, Name varchar(200)
) ;
INSERT INTO HelpTable
VALUES
(1, 'foo', 'A'),
(2, 'bar', 'B'), etc...
;
INSERT INTO Table_A
( A_ID, Field, B_ID)
SELECT HelpTable.A_ID
, HelpTable.Fld
, Table_B.B_ID
FROM HelpTable
JOIN Table_B
ON Table_B.Name = HelpTable.Name
;
DROP TABLE HelpTable ;

Find rows that has ALL the linked rows

I've got two tables:
User (id, name, etc)
UserRight (user_id, right_id)
I want to find the users who have rights 1, 2 and 3, but no users who only have one or two of these. Also, the number of rights will vary, so searches for (1,2,3) and (1,2,3,4,5,6,7) should work with much the same query.
Essentially:
SELECT *
FROM User
WHERE (
SELECT right_id
FROM tblUserRight
WHERE user_id = id
ORDER BY user_id ASC
) = (1,2,3)
Is this possible in MySQL?
SELECT u.id, u.name ...
FROM User u
JOIN UserRight r on u.id = r.user_id
WHERE right_id IN (1,2,3)
GROUP BY u.id, u.name ...
HAVING COUNT DISTINCT(right_id) = 3
You can also do this using PIVOT, especially if you want a visual representation. I did this on SQL Server - you may be able to translate it.
Declare #User Table (id Int, name Varchar (10))
Declare #UserRight Table (user_id Int, right_id Int)
Insert Into #User Values (1, 'Adam')
Insert Into #User Values (2, 'Bono')
Insert Into #User Values (3, 'Cher')
Insert Into #UserRight Values (1, 1)
Insert Into #UserRight Values (1, 2)
Insert Into #UserRight Values (1, 3)
--Insert Into #UserRight Values (2, 1)
Insert Into #UserRight Values (2, 2)
Insert Into #UserRight Values (2, 3)
Insert Into #UserRight Values (3, 1)
Insert Into #UserRight Values (3, 2)
--Insert Into #UserRight Values (3, 3)
SELECT *
FROM #User U
INNER JOIN #UserRight UR
ON U.id = UR.User_Id
PIVOT
(
SUM (User_Id)
FOR Right_Id IN ([1], [2], [3])
) as xx
WHERE 1=1
SELECT *
FROM #User U
INNER JOIN #UserRight UR
ON U.id = UR.User_Id
PIVOT
(
SUM (User_Id)
FOR Right_Id IN ([1], [2], [3])
) as xx
WHERE 1=1
AND [1] IS NOT NULL
AND [2] IS NOT NULL
AND [3] IS NOT NULL
In correspondance with the errors in my answer pointed out, here a solution with count and a subquery:
SELECT *
FROM User
WHERE 3 = (
SELECT Count(user_id)
FROM tblUserRight
WHERE right_id IN (1,2,3)
AND user_id = User.id
)
An optimizer may of course change this to Martin Smith's solution (i.e. by using a group by).