Using GROUP_CONCAT in Mysql Queries - mysql

I have five tables in my database that I am working with. Everything works well till I start selecting states from the database using group concat.
These are my tables:
main_jobs
sub_jobs
category
state
state_job_relationship
Snippet of my table creation
create table if not exists category (
id int(3) not null auto_increment,
parent int(5) not null,
name varchar(255) not null,
description text,
slug varchar(255),
level int (3),
PRIMARY KEY (id, slug));
create table if not exists state (
id int(4) not null auto_increment,
country_id int(11) not null,
name varchar(255) not null,
PRIMARY KEY (id),
FOREIGN KEY (country_id) REFERENCES country (id))";
create table if not exists state_job_relationship (
id int(4) not null auto_increment,
state_id int(4) not null, FOREIGN KEY (state_id) REFERENCES state (id),
job_id int(11) not null, FOREIGN KEY (job_id) REFERENCES sub_jobs (id),
PRIMARY KEY (id));
create table if not exists main_jobs (
id int not null auto_increment, primary key(id),
company_name varchar(255),
job_title varchar(255));
create table if not exists sub_jobs (
id int not null auto_increment, primary key(id),
parent_id int(11) not null, FOREIGN KEY (parent_id) REFERENCES main_jobs (id),
title varchar(255),
description text not null,
category int (3), FOREIGN KEY (category) REFERENCES category (id)
);
This is what I want to select:
The job titles from the sub jobs tables, with the corresponding company name and other details from main_jobs and category table.
All worked well till I needed to select the states each sub_job falls in this format: State1, State2, State3
select sub_jobs.id as kid, main_jobs.id as parentid,
company_name, sub_jobs.description, sub_jobs.title,
job_title, category.name as ind,
DATE_FORMAT($column_date,'%a, %e %b %Y %T') as d,
(select group_concat(name seperator ', ')
from state_job_relationship, state
where job_id= kid
and state.id=state_job_relationship.state_id
group by state.id) states
from sub_jobs, category, main_jobs
where category.id=sub_jobs.category
and main_jobs.id=sub_jobs.parent_id
order by featured desc , $table.id desc
limit 100;
Tried the query above but it displays this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'seperator ', ') from state_job_relationship, state where job_id= kid and state.i' at line 1
Please what am I not getting right?

It looks like your error is because you are using the alais kid inside of the correlated subquery. You should replace the kid with the sub_jobs.id.
Also you have seperator spelled incorrectly.
So your code will be:
select s.id as kid,
m.id as parentid,
company_name,
s.description,
s.title,
job_title,
c.name as ind,
DATE_FORMAT($column_date,'%a, %e %b %Y %T') as d,
(select group_concat(name SEPARATOR ', ')
from state_job_relationship
inner join state
on state.id=state_job_relationship.state_id
where job_id= s.id
group by state.id) states
from sub_jobs s
inner join category c
on c.id=s.category
inner join main_jobs m
on m.id=s.parent_id
order by featured desc , $table.id desc
limit 100;
You will notice that I changed your syntax to use ANSI JOIN syntax and I am using aliasas for the tables.
The other suggestion that I have would be to use a subquery and join to the subquery:
select s.id as kid,
m.id as parentid,
company_name,
s.description,
s.title,
job_title,
c.name as ind,
DATE_FORMAT($column_date,'%a, %e %b %Y %T') as d,
st.states
from sub_jobs s
inner join category c
on c.id=s.category
inner join main_jobs m
on m.id=s.parent_id
left join
(
select job_id, state.id, group_concat(name SEPARATOR ', ') states
from state_job_relationship
inner join state
on state.id=state_job_relationship.state_id
group by state.id, job_id
) st
on st.job_id= s.id
order by featured desc , $table.id desc
limit 100;

Related

Join two data tables in MYSQL and avoid duplicate values

I created two tables using MYSQL, tblorder and tblitem.
CREATE TABLE `tblorder` (
`orderId` int NOT NULL,
`orderName` varchar(45) NOT NULL,
PRIMARY KEY (`orderId`)
CREATE TABLE `tblitem` (
`itemId` int NOT NULL,
`itemName` varchar(45) NOT NULL,
`itemUnit` varchar(5) NOT NULL,
`itemRate` double NOT NULL,
`orderRef` int NOT NULL,
PRIMARY KEY (`itemId`),
KEY `fk1_idx` (`orderRef`),
CONSTRAINT `fk1` FOREIGN KEY (`orderRef`) REFERENCES `tblorder` (`orderId`)
I tried to join the two tables using query below
SELECT orderId,orderName, itemName, itemUnit,itemRate
FROM tblitem
INNER JOIN tblorder on tblorder.orderId = tblitem.orderRef
Now result show like Image-01
How to remove duplicate values in orderId ,OrderName columns in result table?
Thanks to help me to solve this problem.
After joining tables is it possible to get output like below?
Answer for this question is available in below link. https://dba.stackexchange.com/questions/287746/join-two-tables-in-mysql-and-avoid-duplicate-values
SELECT CASE WHEN sortId = 1 THEN CAST(orderId AS CHAR(10)) ELSE '' END AS
orderId, CASE WHEN sortId = 1 THEN orderName ELSE '' END AS orderName,
itemName, itemUnit, itemRate
FROM
(
SELECT orderId, orderName, itemName, itemUnit, itemRate, ROW_NUMBER() OVER
(PARTITION BY orderId ORDER BY itemId) AS sortId
FROM
(
SELECT orderId, orderName, itemName, itemUnit, itemRate, itemId
FROM tblitem
INNER JOIN tblorder
on tblorder.orderId = tblitem.orderRef
) orderItems
) orderItemsSorted
ORDER BY orderItemsSorted.orderId, orderItemsSorted.sortId

how to use left join to output results from a column that are null using two different data types?

hi im having trouble doing a left join that outputs all customers who haven't made an order yet. im getting a conversion error and have tried using cast to convert it but it doesnt work. any help would be appreciated
here are my tables and data:`
create table Customers(
Cust_code varchar(2) primary key ,
[first_name] varchar(30) not null,
last_name varchar(30) not null,
address varchar(100) not null,
city varchar(35) not null)
create table Cust_Order(
order_no int ,
Cust_code varchar(2) not null,
order_date date not null,
meth_pmt varchar(30) not null,
constraint Ord_order_no_pk primary key(order_no),
constraint Cus_cust_code_fk foreign key(Cust_code) references Customers)
create table Product(
product_id int ,
product_name varchar(100) not null,
product_price decimal(8, 2) not null,
constraint Pro_product_id_pk primary key(product_id))
create table Order_Line(
order_no int ,
product_id int ,
qty int not null,
sale_price decimal(8,2) not null,
constraint Ord_order_no_product_id_pk primary key(order_no, product_id),
constraint Pro_product_id_fk foreign key(product_id) references Product)
insert into Customers (Cust_code, [first_name], last_name, address, city)
values('A1', 'Kath', 'Morgan','122 Lilain Street', 'Palmerston North'),
('A2','Mike','Smith','67 Golf Hill Drive','Wellington'),
('A3','Glen','Hoddle','San Quentin Ave','Palmerston North'),
('A4','Dan','Boone','Alamo Road','Wellington')
insert into Cust_Order (order_no, Cust_code, order_date, meth_payment)
values(1, 'A1','2014-01-16','CC'),
(2, 'A1','2014-02-16','CC'),
(3, 'A2','2014-01-16','CHEQUE'),
(4, 'A3','2014-03-17','CC')
insert into Product (product_id, product_name, product_price)
values(1, 'Network Card', 58.00),
(2, 'Motherboard', 150.00),
(3, 'Video Card', 232.00)
insert into Order_Line (order_no, product_id, qty, sale_price)
values(1,1,3,70.00),
(1,2,1,170.00),
(1,3,2,300.00),
(2,1,2,70.00),
(2,3,1,300.00),
(3,1,2,70.00),
(4,1,3,70.00)
my select statement using left join which should output the one customer who hasn't made an order
select first_name + last_name as 'Customers who have not made an order',
order_no from Customers as c
left join Cust_Order as o
on c.Cust_code = o.order_no
where order_no is null
Your join condition needs to match on the customer codes. Other than this, the logic of your query is correct, but MySQL doesn't use + for string concatenation, this is SQL Server syntax. Use the CONCAT function instead:
SELECT
CONCAT(c.first_name, ' ', c.last_name) AS `Customers who have not made an order`
FROM Customers AS c
LEFT JOIN Cust_Order AS o
ON c.Cust_code = o.Cust_code
WHERE o.Cust_code IS NULL;
The ANSI concatenation operator is ||, and you may also use it in MySQL if you set the appropriate mode:
SET sql_mode = PIPES_AS_CONCAT
If you must use a LEFT JOIN, try:
SELECT
CONCAT(C.first_name, ' ', C.last_name) AS 'Customers who have not made an order'
FROM Customers C LEFT JOIN Cust_Order CO
ON C.Cust_code=CO.Cust_code
GROUP BY Customer_FullName
HAVING COUNT(B.*)=0;
Or you can make use of EXISTS.
SELECT
CONCAT(C.first_name, ' ', C.last_name) AS 'Customers who have not made an order'
FROM Customers C
WHERE NOT EXISTS (SELECT NULL FROM Cust_Order CO WHERE C.Cust_code=CO.Cust_code);
See MySQL join made easy for insights on using joins.

SQL - using tables to find out How many types of each book a publisher has

I have two tables, publishers and titles.
I want to find out how many types of each book the publisher has, such as history, childrens, etc.
Here are the two tables:
CREATE TABLE publishers
(
pub_id CHAR(3) NOT NULL,
pub_name VARCHAR(20) NOT NULL,
city VARCHAR(15) NOT NULL,
state CHAR(2) ,
country VARCHAR(15) NOT NULL,
CONSTRAINT pk_publishers PRIMARY KEY (pub_id)
)ENGINE = InnoDB;
CREATE TABLE titles
(
title_id CHAR(3) NOT NULL,
title_name VARCHAR(40) NOT NULL,
type VARCHAR(10) ,
pub_id CHAR(3) NOT NULL,
pages INTEGER ,
price DECIMAL(5,2) ,
sales INTEGER ,
pubdate DATE ,
contract SMALLINT NOT NULL,
CONSTRAINT pk_titles PRIMARY KEY (title_id)
)ENGINE = InnoDB;
All I have been able to do so far is find out the total count of types(genres) of books.
SELECT COUNT(DISTINCT type)
FROM publishers AS a
INNER JOIN titles AS p
ON a.pub_id = p.pub_id;
How can I go about doing this?
You need to have a query with Group By as shown below
SELECT a.pub_id, a.pub_name, p.type, COUNT(DISTINCT p.type)
FROM publishers AS a
INNER JOIN titles AS p ON a.pub_id = p.pub_id
GROUP BY a.pub_id, a.pub_name, p.type
add group by for pub_id and pub_name to avoid two publishers having same name to be considered as one publisher
Try this out: http://sqlfiddle.com/#!9/9331e/24
SELECT p.pub_name, t.type, count(t.type)
FROM publishers AS p
INNER JOIN titles AS t on t.pub_id = p.pub_id
GROUP BY p.pub_id, t.type

select multiple rows from tow tables mysql

I'm trying to select mltiple rows from tow table :
first table is donor
CREATE TABLE donor(
donor_number INT NOT NULL AUTO_INCREMENT,
d_name VARCHAR(30) NOT NULL,
mobile_number INT NOT NULL,
blood_group VARCHAR(20) NULL,
dob DATE NOT NULL,
gender ENUM('male','female') NOT NULL,
govid INT(10) NOT NULL,
PRIMARY KEY (donor_number )
);
second table is blood_donation
CREATE TABLE blood_donation(
donor_number INT NOT NULL,
date_of_donate DATE NOT NULL,
blood_group VARCHAR(20) NULL,
serial_number INT(10) NOT NULL,
blood_component ENUM('wb','prcb') NOT NULL,
PRIMARY KEY (donor_number , date_of_donate ),
FOREIGN KEY (donor_number) REFERENCES donor(donor_number)
);
with this select statement:
SELECT
serial_number,
blood_group
FROM blood_donation
WHERE date_of_donate = '2012-07-18'
UNION ALL
SELECT
blood_group
FROM donor
WHERE donor.donor_number=blood_donation.donor_number;
but, I get error
SQL state 42S22: Unknown column 'blood_donation.donor_number' in 'where clause'
any idea????
Actually you should not be using UNION but JOIN :)
you query will look like this
SELECT
blood_donation.serial_number,
donor.blood_group
FROM
blood_donation ,
donor
WHERE donor.donor_number = blood_donation.donor_number AND date_of_donate = '2012-07-18' ;
A UNION is used to combine more than one result set into a single result set - and each result set must have the same set of columns.
What you need is a JOIN, which is how you link multiple tables together on foreign keys etc and would be something like this:
SELECT
serial_number,
blood_group
FROM blood_donation
INNER JOIN donor ON donor.donor_number=blood_donation.donor_number
WHERE date_of_donate = '2012-07-18'
SELECT
dd.serial_number,
dd.blood_group
FROM blood_donation dd
inner join
donor d
on d.donor_number=dd.donor_number
WHERE dd.date_of_donate = '2012-07-18';
UNION is not what exactly you need, Read some more about JOINS. Also please change the selection alias of columns as per the need. And you can use Left Join instead of Inner Join if you don't want a mandatory join condition on tables.

Why is this LEFT JOIN eliminating records with nothing in the other table?

I have a MySQL Left Join problem.
I have three tables which I'm trying to join.
A person table:
CREATE TABLE person (
id INT NOT NULL AUTO_INCREMENT,
type ENUM('student', 'staff', 'guardian') NOT NULL,
first_name CHAR(30) NOT NULL,
last_name CHAR(30) NOT NULL,
gender ENUM('m', 'f') NOT NULL,
dob VARCHAR(30) NOT NULL,
PRIMARY KEY (id)
);
A student table:
CREATE TABLE student (
id INT NOT NULL AUTO_INCREMENT,
person_id INT NOT NULL,
primary_guardian INT NOT NULL,
secondary_guardian INT,
join_date VARCHAR(30) NOT NULL,
status ENUM('current', 'graduated', 'expelled', 'other') NOT NULL,
tutor_group VARCHAR(30) NOT NULL,
year_group VARCHAR(30) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (person_id) REFERENCES person(id) ON DELETE CASCADE,
FOREIGN KEY (primary_guardian) REFERENCES guardian(id),
FOREIGN KEY (secondary_guardian) REFERENCES guardian(id),
FOREIGN KEY (tutor_group) REFERENCES tutor_group(name),
FOREIGN KEY (year_group) REFERENCES year_group(name)
);
And an incident table:
CREATE TABLE incident (
id INT NOT NULL AUTO_INCREMENT,
student INT NOT NULL,
staff INT NOT NULL,
guardian INT NOT NULL,
sent_home BOOLEAN NOT NULL,
illness_type VARCHAR(255) NOT NULL,
action_taken VARCHAR(255) NOT NULL,
incident_date DATETIME NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (student) REFERENCES student(id),
FOREIGN KEY (staff) REFERENCES staff(id),
FOREIGN KEY (guardian) REFERENCES guardian(id)
);
What I'm trying to select is the first name, last name and the number of incidents for each student in year 9.
Here's my best attempt at the query:
SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p, student s LEFT JOIN incident i ON s.id = i.student
WHERE p.id = s.person_id AND s.year_group LIKE "%Year 9%";
However, it ignores any students without an incident which is not what I want - they should be displayed but with a count of 0. If I remove the left join and the count then I get all the students as I would expect.
I've probably misunderstood left join but I thought it was supposed to do, essentially what I'm trying to do?
Thanks for your help,
Adam
What you are doing is fine, you just missed off the group by clause
SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p, student s LEFT JOIN incident i ON s.id = i.student
WHERE p.id = s.person_id AND s.year_group LIKE "%Year 9%"
GROUP BY p.first_name, p.last_name;
Here's some test data
insert into person values(1, 'student', 'Alice', 'Foo', 'f','1970-01-01');
insert into person values(2, 'student', 'Bob', 'Bar', 'm','1970-01-01');
insert into student values(1,1,0,0,'', 'current','','Year 9');
insert into student values(2,2,0,0,'', 'current','','Year 9');
insert into incident values(1,1,0,0,0,'flu','chicken soup', '2008-01-08');
And here's the output of the query with the group by added to it:
+------------+-----------+------------------+
| first_name | last_name | COUNT(i.student) |
+------------+-----------+------------------+
| Alice | Foo | 1 |
| Bob | Bar | 0 |
+------------+-----------+------------------+
You could further clean up the query by making join clauses from your where clause, and grouping on the person id:
SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p
INNER JOIN student s ON(p.id = s.person_id)
LEFT JOIN incident i ON(s.id = i.student)
WHERE s.year_group LIKE "%Year 9%"
GROUP BY p.id;
Alternately, you could avoid the LEFT JOIN by using a correlated subquery:
SELECT
p.first_name
, p.last_name
, (SELECT COUNT(*) FROM incident i WHERE i.student = s.id)
FROM
person p JOIN student s on s.person_id = p.id
WHERE
s.year_group LIKE "%Year 9%"
You're using count without group by for a start, and you're mixing "where" and "on" syntax for joins.
Try this:
SELECT p.first_name, p.last_name, COUNT(i.student)
FROM person p
JOIN student s on p.id = s.person
LEFT JOIN incident i ON s.id = i.student
WHERE s.year_group LIKE "%Year 9%"
GROUP BY P.id;
Would that not be a left outer join you are looking for? I may have my terminology mixed up? Would not be the first time. But Aron's answer would work.