I have two tables, books and authors. books has a author_id column and a secondary_author_id column (no books have more than two authors). I'm so far doing:
SELECT * FROM books
LEFT JOIN authors
ON books.author_id=authors.id
which is handling the join with the first author. I can't work out how I'd handle the secondary author though. Should I change my schema, or do I just need a bit of SQL help?
SELECT books.*, author1.*, author2.*
FROM books
LEFT JOIN author AS author1
ON author1.author_id = books.author_id
LEFT JOIN author AS author2
ON author2.author_id = books.secondary_author_id
In SQL, you can alias the tables by adding it after the table name. Just be careful, now you'll have duplicate columns, so instead of author1.* you will probably want to alias the results of both author1 and author2.
EDIT
Additional details -- Say you have your basic table (i'll include the details so if people want to test on their own they can):
CREATE DATABASE test;
USE test;
CREATE TABLE books
(
book_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
author_id INT NOT NULL,
secondary_author_id INT
);
CREATE TABLE authors
(
author_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO authors (author_id,name) VALUES (1,'Sue Z. Que'),(2,'John Doe'),(3,'Bob Smith');
INSERT INTO books (book_id,title,author_id,secondary_author_id) VALUES (1,'JOIN-ing Two Tables',1,2);
If you do the select I mention above, your result will be the following:
|----------------------- books TABLE -----------------------------|---- authors table -----|---- authors table ---|
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
| book_id | title | author_id | secondary_author_id | author_id | name | author_id | name |
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
| 1 | JOIN-ing Two Tables | 1 | 2 | 1 | Sue Z. Que | 2 | John Doe |
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
(I've added the top header just for calrity's sake) you see you have two author_id's and two name's (as they are joins of the same table and same column names). BUT, if you alias the columns from the joins like so:
SELECT books.*, author1.name AS primary_author, author2.name AS secondary_author
FROM books
LEFT JOIN authors AS author1
ON author1.author_id = books.author_id
LEFT JOIN authors AS author2
ON author2.author_id = books.secondary_author_id;
You get a much cleaner result:
|----------------------- books TABLE -----------------------------| authors table -|- authors table --|
+---------+---------------------+-----------+---------------------+----------------+------------------+
| book_id | title | author_id | secondary_author_id | primary_author | secondary_author |
+---------+---------------------+-----------+---------------------+----------------+------------------+
| 1 | JOIN-ing Two Tables | 1 | 2 | Sue Z. Que | John Doe |
+---------+---------------------+-----------+---------------------+----------------+------------------+
SELECT books.* FROM books, authors.name, secondary_authors.name
LEFT JOIN authors
ON books.author_id=authors.id
LEFT JOIN authors as secondary_authors
ON books.secondary_author_id=secondary_authors.id
You need to rethink your design, because one day there will be a book with three authors, and the next day there will be a book with zero. (I've been there myself.)
Edit
As your comment says: yes, you need a books_authors table. As long as you have your indexes set up properly, it's not a big performance hit.
The most annoying part is that you're often going to want to string the authors together (one entry per book, concatenating all the authors into a single column). You'll probably end up creating a view for that.
just do another join on the secondary id
Related
I would join my table notifications with 2 different tables, let me present a similar example.
Notifications:
ID | player_id | item_id | ....
Basket player's items
player_id | item_id | note | points | rebounds
Soccer player's items
player_id | item_id | note | match | goal
IMPORTANT: all the player ids are unique, the soccer players are in the format 1******** and the basket players are in the format 5********. so also all the couples player_id - item_id are unique.
The result should be a table like this:
id | player_id | item_id | note | attr1 | attr2
where in "note" there is a note of both kind of players and "attr1" is filled by points or match depends on the player type (same type. INT)
Moreover, the items can be joined with tables SOCCER_ITEMS and BASKET_ITEMS where there are information about the item itself. This JOIN can create duplicated rows because the item_id is not unique between the 2 tables and so a basket item can be joined with the info of a soccer item, creating issues.
is it possible to collect data in the way presented in SQL? I'm writing the code in PHP (don't know if it is useful or not)
You can use the function COALESCE():
SELECT n.id, n.player_id, n.item_id,
COALESCE(s.note, b.note) note,
COALESCE(s.match, b.points) attr1,
COALESCE(s.goal, b.rebounds) attr2
FROM notifications n
LEFT JOIN soccer s ON s.player_id = n.player_id AND s.item_id = n.item_id
LEFT JOIN basket b ON b.player_id = n.player_id AND b.item_id = n.item_id
First of all, i'm sorry to my wrong english.
I have one question for mysql query join with b.limit
show below two table
Table 1 : Members
id INT NOT NULL PRIMARY KEY
user_name VARCHAR(100) NOT NULL
...
Table 2 : Members_opt
id INT NOT NULL PRIMARY KEY
members_id VARCHAR(100) NOT NULL
category varchar(10) NOT NULL
...
and one user have multiple columns of Members_opt.
and Members.id = Members_opt.members_id.
I want make this query
SELECT * FROM Members a, Members_opt b WHERE a.id = b.members_id;
But this query makes below result.
id | user_name | category
01 | John | cat
01 | John | dog
01 | John | bird
02 | olion | cat
03 | jenny | dog
I want if result have same id value, just add "limit 0,1" to category
so i want this result.
01 | John | cat
02 | olion | cat
03 | jenny | dog
How can I achieve this?
The JOIN operation presents all possible combinations of rows in the two tables. So, if John has a dog, cat, and bird, and you do an ordinary JOIN, you'll get three rows for John.
(SELECT .. FROM a,b WHERE a.something=b.something is a JOIN. It uses old-fashioned syntax but is still a JOIN).
To meet your requirement, you need a way to get a virtual table (a subquery) containing just one pet per member.
SELECT members_id,
MAX(category) category
FROM Members_opt
GROUP BY members_id
will do that. It selects the category (pet) with the name coming last in the alphabet. It returns at most one row per value of members_id.
Then you JOIN that virtual table (subquery) to your other table.
SELECT a.id, a.user_name, b.category
FROM Members a
JOIN (
SELECT members_id,
MAX(category) category
FROM Members_opt
GROUP BY members_id
) b ON a.id = b.members_id
This will return one row for each member showing the chosen category. If a member has no categories (no pets) this query will suppress that member's row. If you want your query to show members having no pets, use LEFT JOIN.
Notice that this query
SELECT * /* incorrect: nonstandard, unpredictable */
FROM Members a, Members_opt b
WHERE a.id = b.members_id
GROUP BY a.id
misuses a nonstandard extension to MySQL's implementation of GROUP BY. It won't work in newer versions of MySQL, but rather will get an error. It will, if it does work at all, return unpredictable results. Read this. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Returning unpredictable results is worse than returning random results. When you misuse this GROUP BY hack in MySQL, each subsequent use of the query returns the same results, until it doesn't.
I am trying to write a query for my sports pick application. I want to display all the information from one table, along with 2 columns from another table. I can write the query that selects all the information from one table, but I am having a difficult time writing the query to add the 2 rows to my answer. Here are the two tables that I am using. This is all in Postgresql by the way.
I want to select everything from this table.
Table "public.weekly_stats"
Column | Type | Modifiers
---------+-----------------------+--------------------
week_no | integer | not null
game_no | integer | not null
home | character varying(40) |
away | character varying(40) |
spread | double precision | not null default 0
winner | character varying(40) |
Indexes:
"weekly_stats_pkey" PRIMARY KEY, btree (week_no, game_no)
Foreign-key constraints:
"weekly_stats_away_fkey" FOREIGN KEY (away) REFERENCES team(name)
"weekly_stats_home_fkey" FOREIGN KEY (home) REFERENCES team(name)
And then I want to display the wins and losses for each team. That uses this table...
Table "public.team"
Column | Type | Modifiers
--------+-----------------------+--------------------
name | character varying(40) | not null
wins | integer | not null default 0
losses | integer | not null default 0
Indexes:
"team_pkey" PRIMARY KEY, btree (name)
Referenced by:
TABLE "weekly_stats" CONSTRAINT "weekly_stats_away_fkey" FOREIGN KEY (away)
I can select all the information from the first table
Select week_no, game_no, home, wins, losses, away, wins, losses, spread, winner from weekly_stats inner join team on name.team = weekly_stats.team;
The SQL you posted is trying to use a field weekly_stats.team which doesn't exist. The teams are in weekly_stats.home and weekly_stats.away and since you have two of them, you need two joins.
And to join the same table twice, you need to give it an alias. Here this is done by adding team1 or team2 after the actual name of the table in the joins:
Select
weekly_stats.week_no,
weekly_stats.game_no,
weekly_stats.home,
team1.wins,
team1.losses,
weekly_stats.away,
team2.wins,
team2.losses,
weekly_stats.spread,
weekly_stats.winner
from weekly_stats
inner join team team1 on team1.name = weekly_stats.home
inner join team team2 on team2.name = weekly_stats.away ;
Inner join will work. If there is any possibility that the table team might be missing a team, you could change it to left join which will give you a NULL for the wins/losses where data is missing in the team table.
See if this is what you want:
SELECT `weekly_stats.*`, SUM(`team.wins`), SUM(`team.losses`)
FROM `weekly_stats`
INNER JOIN `team`
ON `team.name` = `weekly_stats.team`
If I misunderstood you, I'm really sorry.
I am having some issues creating this JOIN query.
The table setup is as follows
| tags || tag_links || articles |
|________________||________________||________________|
| | | | | |
| id | | article_id | | id |
| tag_name | | tag_id | | |
There are 3 tables, and this is a many-to-many relationship.
The objective is to find all the tags associated with a given article
id.
The tags table contains all of the tags
The tag_links table contains the link between the articles and the
tags, where the tag_id is equal to the id in the tags table, and the
article_id is equal to the id in the article table
The articles table contains the id ( amongst other columns, but the
other columns are not important )
I am having a hard time because the article id is already provided. I don't think that this is even needed in the query, but I am at a loss right now. I am trying to grab all of the tag_id's that are associated with the article_id that I pass in, and then grab all of the tag_names from all of the tag_id's i just queried for.
Any help is greatly appreciated. Thanks!
This is a simple join you can use to get tag names for a given article id
select distinct t.* from tags t
join tag_links tl on(t.id = tl.tag_id)
where tl.article_id=#id <---- article id
I want to save multiple rows with single id store in table. What should I do? Please guide me.
For example:
| table1 |
|-----------------|
|id |name |
|001(pk) |Ajit |
| table2 |
|-----------------|
|id(FK) |address |
|001 |Pune |
|001 |Mumbai. |
means TWO TABLES are their in table1 id is primary key & table2 id is foreign key
i.e.: 001 id should multiple address it would be save into table2 but id must be same,
i.e.: address textbox will generate at runtime
Put its(id) default value as "001"(you deserve it) using mysql query and then while inserting a new entry leave that column to add as new.
If you're wanting to link the data in the two tables (i.e. a users table and an addresses table) just use a foreign key.
Your users table:
id | name
================
1 | Martin Bean
Your addresses table:
id | user_id | address
==================================
1 1 Newcastle upon Tyne
This way, the primary key of your addresses table is not dependent on the ID of the users table. And your query to fetch both pieces of data is easy with a join:
SELECT
u.id,
u.name,
a.address
FROM
users u
LEFT JOIN
addresses a ON u.id = a.user_id