i just realised i've worded this very poorly
i'm trying to find out if i can do this within an insert statement, not when trying to output the data
This might sound very confusing but hopefully i can explain it.
I have two tables, expertise (parent) and department (child)
In expertise I have :
exp_id int(2) primary key
exp_name varchar(30)
In department I have:
dep_id int(2) primary key
dep_name varchar(30)
exp_id int(2) foreign key
I DO NOT want the outcome for the department rows to look like this:
dep_id dep_name exp_id
1 accounting 32
1 accounting 27
1 accounting 29
I WANT IT to look like this
dep_id dep_name exp_id
1 accounting 32, 27, 29
So there is multiple rows within a row, if that makes any sense.
I believe its concatenation i have to work with, but I've never used this before and was looking for some help
i just realised i've worded this very poorly
i'm trying to find out if i can do this within an insert statement, not when trying to output the data
you should be able to use group_concat, ie:
select dep_id, dep_name, group_concat(exp_id) exp_id
from department
group by dep_id, dep_name
You should also consider normalisation your department table, it is currently violating first normal form due to the repeating groups of dep_id, dep_name. reference here
edit
I see you updated your question to say you want the data stored in this way in the table, not displayed.
The answer to that is: you really don't.
delimited fields are all but impossible to deal with, and are just all around horrible in an rdbms. If you absolutely must have it this way, you could use the above query to create a view, and at least store the real data in a proper, normalised fashion.
To re-iterate. Please don't do this. Kittens will die.
In the spirit of normalized data
-- drop table expertise
create table expertise
( expId int not null,
expName varchar(100) not null
);
insert expertise (expId,expName) values (32,'number massaging');
insert expertise (expId,expName) values (27,'misrepresentation');
insert expertise (expId,expName) values (29,'embezzlement');
-- select * from expertise
-- drop table department;
create table department
( deptId int not null,
deptName varchar(100) not null
);
insert into department (deptId,deptName) values (1,'Accounting');
insert into department (deptId,deptName) values (2,'Executive');
insert into department (deptId,deptName) values (3,'Food Service');
-- select * from department
-- drop table expDeptIntersect;
create table expDeptIntersect
( expId int not null,
deptId int not null
);
insert expDeptIntersect (expId,deptId) values (27,1);
insert expDeptIntersect (expId,deptId) values (32,1);
insert expDeptIntersect (expId,deptId) values (29,1);
--select * from expdeptintersect
select d.deptId,d.deptName,group_concat(i.expId) expId
from department d
join expDeptIntersect i
on i.deptId=d.deptId
group by d.deptId,d.deptName
Related
I have a question for an assignment with 5 tables as shown below. I need to write a query with the minimum cost for each sport:
2nd column is equipment_name:
I think I need to do a bunch of joins in subqueries with the primary keys being the id columns and the foreign keys the name_id columns. Is this the right approach?
You don't need a bunch of joins; minimally this question can be solved by one join between the store_equipment_price and the sports_equipment tables - if these two are joined on equipment id then you'll effectively get rows that can give the cost of starting up in each sport per store. You'll need to group by the sport id and the store id; don't forget that it might be cheaper to start soccer by getting all the gear from store A but it might be cheaper to start golf by going to tore B - tho I how I read the question. If however you're prepared to get your gloves from store A and your bat from store B etc then we don't even group by the store when summing, instead we work out which store is cheapest for each component rather than which store is cheapest for each sport overall.
If you're after producing named stores/sports on your result rows then you'll need more joins but try getting the results right based on the fewest number of joins possible to start with
Both these queries will ultimately be made a lot easier by the use of an analytic/windowing function but these are database dependent; never post an sql question up without stating what your db vendor is, as there are few questions that are pure ISO SQL
You question is not completely clear, I assume you need to find stores from which to buy each equipment for all sports so as to incur minimum expense. Following query will achieve this
select s.sports, e.equipment_name, min(sep.price),
(select store_name from stores st where st.id = sep.store_id) store_name
from sports s
join sports_equipment se on s.id = se.sport_id
join equipment e on e.id = se.equipment_id
join sports_equipment_prices sep on sep.equipment_id = se.equipment_id
group by s.sports, e.equipment_name
order by s.sports, e.equipment_name
;
Following 'create table' and 'insert data' script are based on your screen images
create table sports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sports varchar(50)
);
insert into sports(sports) values('golf');
insert into sports(sports) values('baseball');
insert into sports(sports) values('soccer');
create table stores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
store_name varchar(50)
);
insert into stores(store_name) values('A');
insert into stores(store_name) values('B');
insert into stores(store_name) values('C');
create table equipment (
id INTEGER PRIMARY KEY AUTOINCREMENT,
equipment_name varchar(50)
);
insert into equipment(equipment_name) values('shoes');
insert into equipment(equipment_name) values('ball');
insert into equipment(equipment_name) values('clubs');
insert into equipment(equipment_name) values('glove');
insert into equipment(equipment_name) values('bat');
create table sports_equipment (
sport_id INTEGER not null,
equipment_id INTEGER not null,
FOREIGN KEY(sport_id) REFERENCES sports(id),
FOREIGN KEY(equipment_id) REFERENCES equipment(id)
);
insert into sports_equipment values(1, 1);
insert into sports_equipment values(1, 2);
insert into sports_equipment values(1, 3);
insert into sports_equipment values(2, 2);
insert into sports_equipment values(2, 4);
insert into sports_equipment values(2, 5);
insert into sports_equipment values(3, 1);
insert into sports_equipment values(3, 2);
create table sports_equipment_prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
store_id INTEGER not null,
equipment_id INTEGER not null,
price INTEGER not null,
FOREIGN KEY(store_id) REFERENCES stores(id),
FOREIGN KEY(equipment_id) REFERENCES equipment(id)
);
I have a problem to use WHERE IN with a column value
I have data like below
Table Service
id name sd_ids
1 House Cleaning 1,2
Table Service Detail
id name
1 living room
2 bedroom
Schema
CREATE TABLE IF NOT EXISTS `service` (
`id` int(6) unsigned NOT NULL,
`name` varchar(200) NOT NULL,
`sd_ids` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `service` (`id`, `name`,`sd_ids`) VALUES
('1','House Cleaning','1,2');
CREATE TABLE IF NOT EXISTS `service_detail` (
`id` int(6) unsigned NOT NULL,
`name` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `service_detail` (`id`, `name`) VALUES
('1','living room'),
('2','bedroom');
I already tried this
SELECT *,
(
SELECT
GROUP_CONCAT(name)
from service_detail
where id in(service.sd_ids)
) as service_detail
FROM service;
but the result it's not what I want
id name sd_ids service_detail
1 House Cleaning 1,2 living
I put schema and my testing here
http://sqlfiddle.com/#!9/49c34e/7
What I want to achieve to shows the result like below
id name sd_ids service_detail
1 House Cleaning 1,2 living room,bedroom
I know this schema is not best practice, but I need suggestion to achieve that.
thanks
You may join using FIND_IN_SET in the join criteria:
SELECT
s.id,
s.name,
s.sd_ids,
GROUP_CONCAT(sd.name ORDER BY sd.id) AS service_detail
FROM service s
INNER JOIN service_detail sd
ON FIND_IN_SET(sd.id, s.sd_ids) > 0
GROUP BY
s.id,
s.name,
s.sd_ids;
Demo
In general you should avoid storing CSV data in your SQL tables. CSV data represents unnormalized data, and is difficult to work with (q.v. the above query). Instead, break every service ID onto a separate record for best results.
I have 2 tables, one for the Employees and another for the Departments. A department can have multiple/different employees but one employee may only work in one Department. Their relationship is one to many.
Table Creations:
CREATE TABLE IF NOT EXISTS department(
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
street VARCHAR(255) NOT NULL,
employees_count INT(20) DEFAULT '0')
ENGINE=INNODB;
CREATE TABLE IF NOT EXISTS employee(
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
born INT(20) NOT NULL,
country VARCHAR(255) NOT NULL,
department_name VARCHAR(255) NOT NULL,
FOREIGN KEY (department_name) REFERENCES department(name)
ON UPDATE CASCADE ON DELETE CASCADE)
ENGINE=INNODB;
Table Insertions:
INSERT INTO department(name,street) VALUES ('Alexandroupoli', 'Leoforos Dimokratias21');
INSERT INTO department(name,street) VALUES ('Athens','Basilisis Sofias 111');
INSERT INTO department(name,street) VALUES ('Patras','Smurnis 34');
INSERT INTO department(name,street) VALUES ('Kalamata','Leoforos Fountas 241');
INSERT INTO department(name,street) VALUES ('Heraklion','Leoforos Enetwn 132');
INSERT INTO department(name,street) VALUES ('Thessaloniki','Karolou 45');
INSERT INTO department(name,street) VALUES ('Xanthi','Agia Barbasa 68');
INSERT INTO department(name,street) VALUES ('Larisa','Hroon Polutexneiou 12');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Vaggelis','Michos','vagg7#gmail.com','1995','Greece','Athens');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('James','Gunn','james8#gmail.com','1970','USA','Athens');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('George','McMahon','george95#gmail.com','1978','Usa','Patras');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('John','Jones','john13#gmail.com','1992','England','Patras');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Marinos','Kuriakopoulos','marin_kur#gmail.com','1986','Greece','Alexandroupoli');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Dimitris','Nikolaou','dimitis8#yahoo.gr','1984','Greece','Larisa');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Soufiane','El Kaddouri','sofiane#yahoo.com','1974','France','Xanthi');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Maria','Apostolou','mariamaria1#gmail.com','1997','Greece','Larisa');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Ioannis','Marinou','ioannis_ap#yahoo.gr','1982','Greece','Kalamata');
INSERT INTO employee(first_name,last_name,email,born,country,department_name) VALUES('Thanasis','Athanasiou','thanos89#gmail.com','1989','Cyprus','Heraklion');
UPDATE department SET employees_count = (SELECT COUNT(*) FROM employee WHERE department.name = employee.department_name);
Upon creating the 2 tables and creating a foreign key constraint between them, when I delete a Department from the department table, every assosiated employee get deleted too, just as I need.
BUT, when I delete an employee from the employee table, the employees_count row in department does not change. For example, if I have 2 employees with a department_name = Athens, then upon deleting one of them, when I go to departments table, the employees_count remains equal to 2 instead of 1.
Same thing happens upon updating the department_name in employees table. If for one employee, I update his department_name from "Athens" to lets say "Patras", the department table remains unchanged.
So I was thinking, after I delete an employee, maybe also execute this command
UPDATE department SET employees_count = (SELECT COUNT(*) FROM employee WHERE department.name = employee.department_name);
and that would certainly solve my issue.
BUT, is there a way for the employees_count column in department table to be AUTOMATICALLY assinged to the number of employees that work there instead of just being an integer field?
Is there a more practical way to solve this issue, instead of just adding the UPDATE command after each Deletion I make?
I'd say you don't need to store the department count in the table as a separate attribute; it's a value you can always find out through a query.
Also, deleting records can be very absolute. This is by no means best practice but I prefer to mark records as deleted (maybe with a time stamp). This is information, meta data I guess, that might be of interest. In this way all the employee information is retained. Food for thought.
Hope that was helpful.
create table Student (
St_ID int not null,
St_Name varchar (100),
St_tel int,
St_ADD varchar (100) not null,
St_city varchar (100)not null,
St_type varchar (20) not null,
St_nationality varchar (20) not null,
Dep_ID int,
C_ID int,
primary key (St_ID),
foreign key (Dep_ID) references Department(Dep_ID),
foreign key (C_ID) references Course(C_ID),
)
create table Course (
C_ID int not null,
C_Name varchar (30) not null,
C_Duration varchar (10) not null,
DegreeType varchar (20),
Dep_ID int,
primary key (C_ID),
foreign key (Dep_ID) references Department (Dep_ID),
)
insert into Course Values (4040,'Software Engineering','18months','HND',001)
insert into Course Values (1454,'Business IT','6months','Diploma',001)
insert into Course Values (1534,'Business management ','18months','HND',002)
insert into Course Values (1245,'Digital Media','6months','Diploma',001)
insert into Course Values (1243,'Business Development','10months','Diploma',001)
INSERT INTO Student VALUES (1212,'jerome jacobs',0774750407,'no 66/7 senananyake lane ','nawala','fulltime','HND','SL',001,4040);
INSERT INTO Student VALUES (1713,'john paul',0773435646,'no 77/9 alvatigala lane','colombo ','parttime','Diploma','SL',001,1454);
INSERT INTO Student VALUES (1614,'Angelo mathews',0773436777,'no 88 rose lane colombo ','colombo 2','fulltime','HND','SL',002,1534);
INSERT INTO Student VALUES (1514,'jean paul',0713556688,'no 100/1 4th lane nawala','nawala','fulltime','Diploma','SL',002,1245);
INSERT INTO Student VALUES (1316,'Mark francis',0755657665,'no 54 1st lane ','kotte','parttime','HND','SL',003,4040);
INSERT INTO Student VALUES (1117,'Kevin steffan',0757667687,'no 99/5 railway lane ','nugegoda','parttime','Diploma','SL',004,1243);
SELECT DISTINCT Student.St_ID,St_Name,St_tel,St_ADD,St_type,DegreeType,C_Name from Student,Course where Student.St_type='parttime' and Course.DegreeType='HND';
this is my query to get information from two tables but it repeat values how can i fix that im really curious about sql im a beginner sorry for the way i ask questions i will be reall great full if it is answered
You have to JOIN the tables using the common field:
SELECT DISTINCT Student.St_ID,St_Name,St_tel,St_ADD,St_type,DegreeType,C_Name
from Student JOIN
Course ON Student.C_ID =Course.C_ID
where Student.St_type='parttime' and Course.DegreeType='HND';
An SQL JOIN clause is used to combine rows from two or more tables, based on a common field between them.
Read more about joins here.
You have to use MySql Join , if you need to understand it more : http://dev.mysql.com/doc/refman/5.0/en/join.html
You have to join the student and course tables together by specifying their common column (key). Instead of this:
from Student,Course
do this:
from Student
join Course on student.C_ID= Course.C_ID
If you don't connect the two tables properly you'll get the cartesian product set.
Click for Information JOIN
SELECT S.St_ID, St_Name, St_tel, St_ADD, St_type, DegreeType, C_Name
FROM Student s
INNER JOIN Course C ON S.C_ID = C.C_ID
WHERE S.St_type='parttime' and C.DegreeType='HND'
GROUP BY S.St_ID;
I have a table called 'users' that contains fields such as
username
DOB
gender
etc
Each user can save their plants on a table called 'plants' that has the following fields
username
plant
So user 'johndoe' would show on table 'plants' as follows:
johndoe -> lilly
johndoe -> orchid1
johndoe -> orchid2
johndoe -> fern1
johndoe -> fern2
Questions:
Is this a bad way of setting up my tables? I ask because when the number of users grows, then there will be hundreds of rows, several of which with repeated usernames because each user will likely have more than one plant. Would this slow down queries?
If I make one plant table per user, I think that would increase dramatically the number of DB requests and create an enormous amount of tables in the DB.
Another option would be to have separate tables for lilly, orchid, fern, etc with fields such as
username
but then I would still have several rows with repeated usernames.
Any suggestions?
Normalize your tables. Add id field to users and store that id in plants instead of the username.
Further, read more about normalization principles and try to apply them in practice.
In stead of using the username I would use an INT id. Like so:
userid
username
DOB
gender
etc
and for your plants:
plantid
userid_fk
plantname
And then join on users.userid = plants.userid_fk to find the matches :)
That's a perfectly reasonable way (your initial proposal) to set things up; that's what relational databases are for.
You're doing a classic many-to-many relationship in your plants table. Each user can have several plants, and each plant may have several users.
For better efficiency, you could use an id to refer to your users instead of a user name. In most relational databases, an id is a row number, and is a very efficient (and compact) reference.
Here's how I'd go about this, with an example database script and query:
Create/Load Users Table - Using a surrogate primary key instead of the username since queries will be faster against INTs and they can conceivably change.
CREATE TABLE users (
id int(11) AUTO_INCREMENT NOT NULL,
username varchar(255) NOT NULL,
gender char(1) NULL,
PRIMARY KEY(id)
) ENGINE = MyISAM AUTO_INCREMENT = 3
Load Users
INSERT INTO users(id, username, gender)
VALUES(1, 'john', NULL)
GO
INSERT INTO users(id, username, gender)
VALUES(2, 'jane', NULL)
GO
Create Plants
CREATE TABLE plants (
id int(11) AUTO_INCREMENT NOT NULL,
name varchar(200) NOT NULL,
PRIMARY KEY(id)
) ENGINE = MyISAM AUTO_INCREMENT = 6
Load Plants
INSERT INTO plants(id, name)
VALUES(1, 'fern1')
GO
INSERT INTO plants(id, name)
VALUES(2, 'fern2')
GO
INSERT INTO plants(id, name)
VALUES(3, 'orchid1')
GO
INSERT INTO plants(id, name)
VALUES(4, 'orchid2')
GO
INSERT INTO plants(id, name)
VALUES(5, 'lilly1')
Create Join Table I use a surrogate primary key here since so many web platforms won't properly update a join table with a 2 column primary. Also, I've ended up adding meta data / details to these types of joins quite often, and it gets messy without it. Note I don't restrict the combination of the same user adding the same plant type, but you can easily.
CREATE TABLE plants_users (
id int(11) AUTO_INCREMENT NOT NULL,
plant_id int(11) NOT NULL,
user_id int(11) NOT NULL,
PRIMARY KEY(id)
)
ENGINE = MyISAM
AUTO_INCREMENT = 8
GO
CREATE INDEX fk_plant_id USING BTREE
ON plants_users(plant_id)
GO
CREATE INDEX fk_user_id USING BTREE
ON plants_users(user_id)
Load Join Table
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(1, 1, 1)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(2, 2, 1)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(3, 3, 1)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(4, 4, 1)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(5, 2, 2)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(6, 3, 2)
GO
INSERT INTO plants_users(id, plant_id, user_id)
VALUES(7, 5, 2)
Final Query:
select
users.username,
plants.name
from
users,plants,plants_users
where
users.id = plants_users.user_id and
plants.id = plants_users.plant_id
Result:
user name
john fern1
john fern2
john orchid1
john orchid2
jane fern2
jane orchid1
jane lilly1