Scenario:
I've been trying to solve a problem where I wanted to make a natural join between two tables Artists and Albums, where Artists cointains a column ar_id that is the primary key and Albums contains a column also named ar_id where the foreign key in the Album table is ar_id and refers to Artists ar_id. There's a 1 to many relationship between the tables (one artist can have multiple albums).
Problem:
When I want to make a NATURAL JOIN between the two tables Artists and Albums it returns 0 rows, but when I use are normal JOIN with WHERE function it returns 18 rows as it should. So I guess the problem is the foreign key setup but I can't find the problem
The select code with natural join (doesn't work):
SELECT * FROM
Artists NATURAL JOIN Albums;
The select code with normal join where (does work):
SELECT * FROM
Artists JOIN Albums
WHERE CDReg.Artists.ar_id = CDReg.Albums.ar_id;
DLL for the two tables
CREATE TABLE Artists (
ar_id int PRIMARY KEY,
ge_id int(11) DEFAULT NULL,
country_code varchar(2) DEFAULT NULL,
name varchar(45) NOT NULL,
start_year year(4) DEFAULT NULL,
end_year year(4) DEFAULT NULL,
FOREIGN KEY (ge_id) REFERENCES Genres (ge_id),
FOREIGN KEY (country_code) REFERENCES Countries (code)
);
-- --------------------------------------------------------
CREATE TABLE Albums (
al_id int PRIMARY KEY,
ar_id int,
name varchar(45) NOT NULL,
release_year year(4) DEFAULT NULL,
FOREIGN KEY (ar_id) REFERENCES Artists(ar_id)
);
Thanks for any help in advance :)
[SOLVED]:
I thought that natural join used the foreign key to join the tables but instead it uses all matching column names including the columns "name" (exsists in both tables), since there isn't any artists with an eponymous album title in the database the result was 0 rows. The solution was to use
SELECT * FROM
Artists JOIN albums USING(ar_id);
From the documentation:
The NATURAL [LEFT] JOIN of two tables is defined to be semantically
equivalent to an INNER JOIN or a LEFT JOIN with a USING clause that
names all columns that exist in both tables.
Both tables have a column name which is included in the natural join, making it fail for all combinations except for those where the artist and album names are the same (which I guess could happen).
You could use a join FROM Artists JOIN albums USING (ar_id) instead.
The natural join probably use namein the join which leads to 0 results unless an artist has an eponymous album!
Anyhow you should avoid natural join because, as you can see, they are less obvious. Stick to the normal join version.
Related
Hello and welcome to my question
I have this table:
CREATE TABLE IF NOT EXISTS business(
businessname varchar(250) NOT NULL,
title varchar(250) NOT NULL,
registerdate datetime NOT NULL,
id int NOT NULL,
city varchar(50) NOT NULL,
tk varchar(10) NOT NULL,
number varchar(20) NOT NULL,
branch int,
doy_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (branch) REFERENCES business(id)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (doy_id) REFERENCES doy(id_kataxorisis)
ON DELETE CASCADE ON UPDATE CASCADE
)
As you can see this table represents a company, poorly but it does.
The branch column represents the "child" of a company
I want to find (with a select statement) the name of each company and its parent company, if the company has no parent company then it should display NULL.
I have been thinking of this for some time and I don't even know how to begin. Could you please help me?
You can join the table with itself. You must add aliases to each instance of the table the query includes.
For example, you can do:
select
c.id, c.businessname,
p.id, p.businessname
from business c
left join business p on p.id = c.branch
Note: The query uses a LEFT JOIN to ensure you see companies that do not have a parent row. In this case it shows nulls in the place of the parent values.
Been reading up on this (for ages!) and can't get clear picture.
First, if I have two tables (e.g. recipes and ingredients) with a many-to-many relationship and I create a intermediary/relational table, how do I write an SQL query to to find all recipes with, say, bananas in them?
Second, why would I have this third relational table if I can find the same information using JOIN queries without the third tables creation??
Really appreciate a clear, helpful explanation, thanks.
how do I write an SQL query to to find all recipes with, say, bananas in them?
You can do:
select distinct r.id, r.name
from recipe r
join recipe_ingredient ri on ri.id_recipe = r.id
join ingredient i on i.id = ri.id_ingredient
where i.name = 'banana'
Second, why would I have this third relational table if I can find the same information using JOIN queries without the third tables creation?
Since a recipe can have many ingredients, and an ingredient can be related to many recipies the relationship between those two tables is not 1:n but n:m. Therefore, you need an intermediate table, as shown below:
create table recipe (
id int primary key not null,
name varchar(20)
);
create table ingredient (
id int primary key not null,
name varchar(20)
);
create table recipe_ingredient (
id int primary key not null,
id_recipe int not null,
id_ingredient int not null,
quantity double not null,
foreign key fk1 (id_recipe) references recipe (id),
foreign key fk2 (id_ingredient) references ingredient (id)
);
If an ingredient showed up in a single recipe always, the structure would be simpler, as you seem to think. This simpler structure would probably look like:
create table recipe (
id int primary key not null,
name varchar(20)
);
create table ingredient (
id int primary key not null,
name varchar(20),
id_recipe int not null,
foreign key fk3 (id_recipe) references recipe (id)
);
A model like this one is not really practical in this case. You would end up having the same ingredient multiple times. For example, if a cake uses "flour" and bread uses "flour", then "flour" would end up twice in the ingredients table. Not a great idea.
I'm trying to join multiple tables to have a view that can act as a report, but I'm confused as to why the I'm getting the MySQL ERROR 1060 (42S21): Duplicate column name 'storeNum'
I have tried using Left Join as from what I understand it looks for the same columns and then joins the tables based on the shared column where the columns that are joined are the ones that differ between the table.
All of the tables are connected by a foreign key.
Create view AR_Report as
select * from AR Left JOIN fullStoreList ON
AR.storeNumber = fullStoreList.storeNum
Left JOIN AR_po ON AR.storeNumber = AR_po.storeNum
Left JOIN AR_call ON AR.storeNumber = AR_call.storeNum
Left JOIN AR_prep ON AR.storeNumber = AR_prep.storeNum;
Create table AR(workOrder varchar(10)
primary key unique not null,
storeNumber int UNIQUE, FOREIGN KEY (storeNumber)
REFERENCES fullStoreList (storeNum));
// where all tables should feed into
Create table AR_call(storeNum int primary key unique not null, FOREIGN KEY (storeNum) REFERENCES AR (storeNumber), .... );
// AR_call, AR_prep and AR_po start like this
Create table fullStoreList( storeNum int primary key UNIQUE
not null, ...);
I can post the full create table statements, they are just really long.
I was expecting the view to have all the columns from the other tables be connected by the AR table without the storeNum being present multiple times.
I am very new to MySQL and am just trying to understand it more.
If this question is a little vague just let me know and I will provide more info.
I have written a query that gets data from multiple tables but it isn't working how I expected it too and I am completely stumped.
Here is my code:
SELECT students.student_fname, students.student_lname
FROM students, enrolments
WHERE enrolments.courseID = 'C001';
but this just returns all of the students first and last names in the students table and these names are displayed twice.
Here is the code for the two tables:
CREATE TABLE students
(
studentID CHAR(10) NOT NULL,
student_fname VARCHAR(15) NOT NULL,
student_lname VARCHAR(15) NOT NULL,
DOB VARCHAR(10) NOT NULL,
CONSTRAINT pk_students PRIMARY KEY (studentID)
);
CREATE TABLE enrolments
(
enrolmentNo int NOT NULL AUTO_INCREMENT,
studentID CHAR(10) NOT NULL,
courseID CHAR(4) NOT NULL,
CONSTRAINT pk_enrolments PRIMARY KEY (enrolmentno),
FOREIGN KEY (studentID) REFERENCES students (studentID),
FOREIGN KEY (courseID) REFERENCES courses (courseID)
)ENGINE = INNODB;
This is because you've not defined how students relate to enrolments.
You either need to use an inner join or add a where clause that show how they relate.
For example:
FROM Students
INNER JOIN enrolments on Students.ID = enrolments.studentID
Or
FROM students, enrolements
WHERE enrolments.studentID = students.ID
The first method is newer and preferred by many; but the legacy method is also supported.
To gain a better understanding of table joins take a look at this most excellent article: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Otherwise you get what is called a Cartesian product of the two tables all data relates to all data.
If you do not have a unique index on enrolements (a student can only have 1 class enrolment) then a select Distinct field names or where... group by fields will also limit your results to close to what you're looking for as well.
============================ in response to follow-up comment===================
SELECT S.student_fname, S.student_lname
FROM students S
INNER JOIN enrolments E
ON S.StudentID = E.StudentID
WHERE e.courseID = 'C001'
GROUP BY S.Student_Fname, S.Student_lname
ORDER BY S.Student_LName, S.Student_FName
The group by eliminates duplicates for the same course.
The "ON statement tells the database how students relates to enrolments.
The order by is just to provide a reasonable order to results.
You cannot fetch data from two tables in this way. You have to join tables.
I am having a little bit of a problem with setting up a mysql table that will hold a list of categories and subcategories. I am not to sure how to setup the table. Does it need to be 2 separate tables? 1 for the main categories and 1 for the subcategories or can it be all in 1 table? Would something like this work?
Create Table categories (
category_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sub_id INT UNSIGNED NOT NULL,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (category_id)
)
CREATE TABLE items (
item_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description VARCHAR(100) NOT NULL,
PRIMARY KEY (item_id),
FOREIGN KEY (category_id) REFERENCES categories (category_id),
FOREIGN KEY (sub_id) REFERENCES categories (sub_id)
)
Will this work or is this completely wrong? Thanks in advance for the help!
If you are 100% sure that you'll only have two levels of categories (main and sub), you can do a few different things. None of them are your proposed solution:
CREATE TABLE categories (
id int not null primary key,
main varchar(64)
sub varchar(64)
);
CREATE TABLE objects (
id int not null primary key,
category_id int,
name varchar(64),
FOREIGN KEY (category_id) REFERENCES categories (id)
);
Want all vehicles?
SELECT *
FROM objects AS o
INNER JOIN categories AS c ON o.category_id = c.id
WHERE c.main = 'vehicles';
Want all roflcopters?
SELECT *
FROM objects AS o
INNER JOIN categories AS c ON o.category_id = c.id
WHERE c.main = 'vehicles' and c.sub='Roflcopters';
If you want something in the "vehicle" category, but not in any of the subcategories of verhicles, just have a category record where main='vehicles' with sub NULL.
Of course, this is not particularly flexible. You're stuck with just two levels of categorization, and there's not a lot of business logic embedded in your category model. But it might be sufficient for your needs.
Two other good, proven, models are the adjacency list model, and the nested set model, both of which are described, with lots of nice example mysql code, over here
It depends.
Are categories and subcategories really two different things? This means categories have no parent, while subcategories are always in a parent category and have no further subs of themselves. Then two tables is ok.
If it's like a tree though, where there are just categories, which can both be children and have children, you should use one table (Google "nested set").
(Or maybe you don't mean category/subcategory but primary category/secondary category, where the secondary category is not fixed to a certain primary category. Electronics + Cycling instead of Cycling->Speedometers. Then you could use one table if it could also be Cycling + Electronics)
It is obviously work. But you may use separate tables.
create table categories
(
categoryId int not null,
categoryName varchar(20) not null,
primary key(categoryId)
);
create table subcategories
(
subcategoryId int not null,
subcategoryName varchar(20) not null,
parentId int not null,
primary key(subcategoryId),
foreign key(categoryId) references categories(categoryId)
);
create tables items
(
item_id int unsigned not null auto_increment,
name varchar(255) not null,
description varchar(100) not null,
primary key(item_id),
foreign key(categoryId) references categories(categoryId),
foreign key(subcategoryId) references subcategories(subcategoryId)
)