I have two tables- students and subjects. Student table stores list of all student and subject table stores all the subjects that these students have been enrolled into.
CREATE TABLE students
(`id` int, `name` varchar(7));
INSERT INTO students
(`id`, `name`)
VALUES
(1, 'Jason'),
(2, 'Matt'),
(3, 'Abram')
;
CREATE TABLE subjects
(`id` int,`student_id` int, `subject` varchar(15));
INSERT INTO subjects
(`id`,`student_id`, `subject`)
VALUES
(1,1, 'Math'),
(2,1, 'Physics'),
(3,2, 'Chemistry'),
(4,2, 'Math'),
(5,2, 'English'),
(6,3, 'Chemistry')
;
And upon executing the following query
SELECT STUD.id,STUD.name,SUB.subject
FROM students AS STUD
LEFT JOIN subjects AS SUB
ON STUD.id=SUB.student_id
;
gives a result set like this (which is not what I am trying to get)
++++++++++++++++++++++++++++++++++++
id | name | subject |
++++++++++++++++++++++++++++++++++++
| 1 | Jason | Math |
------------------------------------
| 1 | Jason | Physics |
------------------------------------
| 2 | Matt | Chemistry |
------------------------------------
| 2 | Matt | Math |
------------------------------------
| 2 | Matt | English |
------------------------------------
| 3 | Abram | Chemistry |
------------------------------------
The students gets repeated in the list.
And when I try
SELECT STUD.id,STUD.name,SUB.subject
FROM students AS STUD
LEFT JOIN subjects AS SUB
ON STUD.id=SUB.student_id
GROUP BY STUD.id
;
I get (which is again wrong)
++++++++++++++++++++++++++++++++++++
id | name | subject |
++++++++++++++++++++++++++++++++++++
| 1 | Jason | Math |
------------------------------------
| 2 | Matt | Chemistry |
------------------------------------
| 3 | Abram | Chemistry |
------------------------------------
My Desired result looks like this:
++++++++++++++++++++++++++++++++++++++++++++++++
id | name | subject |
++++++++++++++++++++++++++++++++++++++++++++++++
| 1 | Jason | Math, Physics |
------------------------------------------------
| 2 | Matt | Chemistry,Math ,English |
------------------------------------------------
| 3 | Abram | Chemistry |
------------------------------------------------
I am a novice in Relational databases.
Why is group by not giving correct result?
Thanks in advance.
SQL FIDDLE
You can achieve this by
SELECT STUD.id,STUD.name,GROUP_CONCAT(SUB.subject) as subject
FROM students AS STUD
LEFT JOIN subjects AS SUB
ON STUD.id=SUB.student_id
GROUP BY STUD.id;
Actually it gives correct result when you have group by some column in sql it will returns only first record in group so for your desired result you needs to used GROUP_CONCAT function which return all comma separated values in given column.
Related
I'm new to sql and do not understand what this join statement is doing. Does this statement ON people.state_code=states.state_abbrev mean that people.state_code and states.state_abbrev are now one?
SELECT people.first_name,
people.state_code, states.division
FROM people
JOIN states ON people.state_code=states.state_abbrev;
It will take the columns first_name and state_code from the table people and the column division from the table states and put them together in a join table where the entries in the state_code and state_abbrev columns match. The join table is produced only for display in response to this query; the underlying tables with the data entries are not amended.
In this case the '=' means equal (like values are equal) and is part of the join condition based on which data is retrieved by the select statement. You are 'linking' the two tables based on a condition so you can retrieve related data...
Relational data base - there are relations between tables and between data.
For example:
table_1
PERSON_ID FIRST_NAME LAST_NAME ADDRESS_ID
1 |John |Doe |2
table_2
ADRESS_ID STREET
1 | 5th Avenue
2 | 1st Street
SELECT FIRST_NAME, STREET
FROM table_1 t1
JOIN table_2 t2 ON t1.ADDRESS_ID = t2.ADDRESS_ID;
will return
John, 1st Street
Does this statement ON people.state_code=states.state_abbrev mean that people.state_code and states.state_abbrev are now one?
Answer: NO. people.state_code and states.state_abbrev should be the same value on the respective tables.
Let me give you an example taken from https://www.mysqltutorial.org/mysql-join/
Suppose you have below tables:
CREATE TABLE members (
member_id INT AUTO_INCREMENT,
members_name VARCHAR(100),
PRIMARY KEY (member_id)
);
CREATE TABLE committees (
committee_id INT AUTO_INCREMENT,
committees_name VARCHAR(100),
PRIMARY KEY (committee_id)
);
Some data examples:
+-----------+--------+
| member_id | members_name |
+-----------+--------+
| 1 | John |
| 2 | Jane |
| 3 | Mary |
| 4 | David |
| 5 | Amelia |
+-----------+--------+
+--------------+--------+
| committee_id | committees_name |
+--------------+--------+
| 1 | John |
| 2 | Mary |
| 3 | Amelia |
| 4 | Joe |
+--------------+--------+
To do the INNER JOIN we can use members_name and committees_name not the id because they are auto_increment and the data are not related.
So the query would be:
SELECT
m.member_id,
m.members_name AS member,
c.committee_id,
c.committees_name AS committee
FROM members m
INNER JOIN committees c ON c.name = m.name;
Giving below result:
+-----------+--------+--------------+-----------+
| member_id | member | committee_id | committee |
+-----------+--------+--------------+-----------+
| 1 | John | 1 | John |
| 3 | Mary | 2 | Mary |
| 5 | Amelia | 3 | Amelia |
+-----------+--------+--------------+-----------+
Conclusion: The values of the columns are equaly the same
I created a table of employees. Some of those employees report to other employees defined in the same table. Let's call them managers.
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
managerID INT NULL,
FOREIGN KEY (managerID) REFERENCES employees (id) ON DELETE RESTRICT
) ENGINE=INNODB;
Then, some values are entered in the database:
INSERT INTO employees(id, name, managerID)
VALUES (1, "Ivan", NULL),
(2, "Peter", 1),
(3, "Alexandra", 1),
(4, "Maria", 2),
(5, "Marian", 2),
(6, "Margarita", 3),
(7, "Mihail", 3),
(8, "Eva", 6);
I want a SELECT query which returns all employees and all the managers they report to. For now the next best thing I have is this:
SELECT employee.name AS Name, manager.name AS `Reports to:`
FROM employees,
LEFT JOIN employees AS manager ON employee.managerID = manager.id;
Which has predictable output:
Employee Reports to:
Ivan NULL
Peter Ivan
Alexandra Ivan
Maria Peter
Marian Peter
Margarita Alexandra
Mihail Alexandra
Eva Margarita
What I want is a such SELECT query that will return a variable number of columns based on the fact how many managers a single employee has. It's apparent to me that a recursive SELF JOIN will be required, but I don't know how to tell the DBMS I want a variable number of columns for each row and I don't know how to phrase the condition.
Desired output:
I understand that you want to generate a resultset where each record corresponds to an employee, with columns that show all managers of that employee (manager of the employee, then manager of the manager, etc...).
The thing to keep in mind is that a SQL query must return a fixed set of columns. The RDBMS needs to know in advance how many columns will be returned by the query to be able to parse it and execute it.
Here is a solution that can handle up to 5 levels of management. It workds by extending your logic with more LEFT JOINs. It's not pretty, but it works. You can add mor joins to handle more management levels.
SELECT
e0.name AS Name,
e1.name AS Manager1,
e2.name AS Manager2,
e3.name AS Manager3,
e4.name AS Manager4,
e5.name AS Manager5
FROM employees e0
LEFT JOIN employees e1 ON e1.id = e0.managerID
LEFT JOIN employees e2 ON e2.id = e1.managerID
LEFT JOIN employees e3 ON e3.id = e2.managerID
LEFT JOIN employees e4 ON e4.id = e3.managerID
LEFT JOIN employees e5 ON e5.id = e5.managerID
In this DB Fiddle with your sample data, the query returns:
| Name | Manager1 | Manager2 | Manager3 | Manager4 | Manager5 |
| --------- | --------- | --------- | -------- | -------- | -------- |
| Ivan | | | | | |
| Peter | Ivan | | | | |
| Alexandra | Ivan | | | | |
| Maria | Peter | Ivan | | | |
| Marian | Peter | Ivan | | | |
| Margarita | Alexandra | Ivan | | | |
| Mihail | Alexandra | Ivan | | | |
| Eva | Margarita | Alexandra | Ivan | | |
This is branch detail table which have the branch name and the employee id work on that branch.
CREATE TABLE Branch_detail
(`nid` int,`branch` varchar(15), `emp_with_department` varchar(15));
INSERT INTO Branch_detail
(`nid`,`branch`, `emp_with_department`)
VALUES
(1,'Mumbai', '1,2,4'),
(2,'Banglore', '4,5');
| nid | branch | emp_with_department |
|-----|----------|---------------------|
| 1 | Mumbai | 1,2,4 |
| 2 | Banglore | 4,5 |
This is employee detail table with their respective designations.
CREATE TABLE Emp
(`id` int, `name` varchar(10), `Designations ` varchar(10));
INSERT INTO Emp
(`id`, `name`,`Designations `)
VALUES
(1,'Rantesh', 'Executive'),
(2,'Keith', 'Art'),
(3,'Nikhil', 'Executive'),
(4,'Gauresh', 'Art'),
(5,'Sumit', 'Executive');
| id | name | Designations |
|----|---------|--------------|
| 1 | Rantesh | Executive |
| 2 | Keith | Art |
| 3 | Nikhil | Executive |
| 4 | Gauresh | Art |
| 5 | Sumit | Executive |
This query i tried to get atleast which id is Executive or Art employee
SELECT a.nid,
GROUP_CONCAT(b.Designations ORDER BY b.id) Designations_Name
FROM Branch_detail a INNER JOIN Emp b
ON FIND_IN_SET(b.id, a.emp_with_department) > 0
GROUP BY a.nid
| nid | Designations_Name|
|-----|-------------------|
| 1 | Executive,Art,Art |
| 2 | Art,Executive |
Output should be:
count of Executives for nid=1,
count of Art for nid=1,
count of executives for nid=2,
count of Art for nid=1
OR
| nid | count(Designations_Name)|
|-----|--------------------------|
| 1 | 1,2,2 |
| 2 | 1,1 |
I want the Output like there on n location, how many executive and art employee is present in count ?
this is sqlfiddle where the demo is present
http://sqlfiddle.com/#!9/27aa51/1
Although you should implement Normalization.
But still, here is a query which will work for you, utilizing Nested Queries:
select inner_nest.nid, GROUP_CONCAT(designations_count)
FROM (SELECT a.nid, b.Designations, COUNT(DISTINCT b.id) as designations_count
FROM Branch_detail a
INNER JOIN Emp b ON FIND_IN_SET(b.id, a.emp_with_department) > 0
WHERE 1 = 1
GROUP BY a.nid, b.Designations ) AS inner_nest
GROUP BY inner_nest.nid
It gets Count for Art first, then Executives (as alphabetically Art comes first)
SELECT
e.*,
(
SELECT GROUP_CONCAT(topic_name)
FROM topic
WHERE id IN (e.topic_ids)) AS topics
FROM exam e
result :
topics = xyz topic
this query returns a single name of topic as result but when i use this :
SELECT
e.*,
(
SELECT GROUP_CONCAT(topic_name)
FROM topic
WHERE id IN (1,4)) AS topics
FROM exam e
result :
topics = xyz topic,abc topic
That works fine,and exam table had the same value in DB (comma separated topic ids = 1,4) as varchar type field.
is there any issue with datatype of field?
First, let me lecture you about how bad CSV in field is.
| id | topic_ids |
|----|-----------|
| 1 | a,b,c |
| 2 | a,b |
This, is how Satan look like in relational DB. Probably the worst, just after the
"lets put columns as line and use a recursive join to get everything back."
How it should be ?
exam
| id |
|----|
| 1 |
| 2 |
exam_topic
| exam_id | topic_id |
|---------|----------|
| 1 | a |
| 1 | b |
| 1 | c |
| 2 | a |
| 2 | b |
topic
| id |
|----|
| a |
| b |
| c |
Now, as awful as it may be, this is the "dynamic" alternative, using FIND_IN_SET() :
SELECT
e.*,
(
SELECT GROUP_CONCAT(topic_name)
FROM topic
WHERE FIND_IN_SET(id, e.topic_ids) > 0
) AS topics
FROM exam e
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE exam
(`id` int, `topic_ids` varchar(5))
;
INSERT INTO exam
(`id`, `topic_ids`)
VALUES
(1, 'a,b,c'),
(2, 'a,b'),
(3, 'b,c,d'),
(4, 'd')
;
CREATE TABLE topic
(`id` varchar(1), `topic_name` varchar(4))
;
INSERT INTO topic
(`id`, `topic_name`)
VALUES
('a', 'topA'),
('b', 'topB'),
('c', 'topC'),
('d', 'topD')
;
Query 1:
SELECT
e.*,
(
SELECT GROUP_CONCAT(topic_name)
FROM topic
WHERE FIND_IN_SET(id, e.topic_ids) > 0
) AS topics
FROM exam e
Results:
| id | topic_ids | topics |
|----|-----------|----------------|
| 1 | a,b,c | topA,topB,topC |
| 2 | a,b | topA,topB |
| 3 | b,c,d | topB,topC,topD |
| 4 | d | topD |
Starting with a single table (user_import) brought in from .csv
| Name | Login | Email | CustomA | CustomB |
+------------+-------+----------------------+---------+---------+
| John Smith | johns | john_smith#gmail.com | Blarg | Narx |
| Max Power | maxp | max_power#gmail.com | Jarg | Lipdo |
+------------+-------+----------------------+---------+---------+
Attempting to have it populate a Joomla! users table
| id | name | username | email | ...
| 514 | Super User | admin | admin#gmail.com | ...
| 515 | John Smith | johns | john_smith#gmail.com | ...
| 516 | Max Power | maxp | max_power#gmail.com | ...
and insert any custom custom fields to the user_profiles table
+---------+-------------------------------------+---------------+----------+
| user_id | profile_key | profile_value | ordering |
+---------+-------------------------------------+---------------+----------+
| 515 | customprofile.custom_a | "Blarg" | 1 |
| 515 | customprofile.custom_b | "Jarg" | 2 |
| 516 | customprofile.custom_a | "Narx" | 1 |
| 516 | customprofile.custom_b | "Lipdo" | 2 |
+---------+-------------------------------------+---------------+----------+
I don't think there is a way to do this in a single call as the user_id has to auto_increment
First query is pretty strait forward
INSERT INTO prknc_users (name, username, email, params, password)
SELECT Name, Login, Email, '{}', 'tuChaSw-tEte72_!eSW#muc3#trew8steZacra2e7a7R6yuqAyeSAXUy=Stu'
FROM user_import;`
The second one is the one I need some help with, tried with this for one:
INSERT INTO user_profiles (user_id, profile_key, profile_value, ordering)
SELECT (SELECT users.id FROM users, user_import WHERE users.email = user_import.Email), 'customprofile.custom_a',user_import.CustomA, '1'
FROM user_import;
Failing hard. Please help me out if you can.
You can try an application like this
https://gist.github.com/elinw/5b579e18b9613f08330d
Just make sure to make the changes that make sense in your use case .
Inner select can return multiple values and not insync with other colums in the outer select. You should move the last three columns into the first select.
INSERT INTO user_profiles (user_id, profile_key, profile_value, ordering)
(SELECT users.id, 'customprofile.custom_a',user_import.CustomA, '1'
FROM users, user_import
WHERE users.email = user_import.Email)
INSERT INTO user_profiles (user_id, profile_key, profile_value, ordering)
SELECT users.id,'customprofile.custom_b',user_import.CustomB, '2'
FROM users, user_import
WHERE users.email = user_import.Email
UNION
SELECT users.id,'customprofile.custom_a',user_import.CustomA, '1'
FROM users, user_import
WHERE users.email = user_import.Email;