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.
Related
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 working on a project where I need to store an unknown length list on names in an sql db. It will be a list of students in a class, which will be different for each class. I also need to be able to search for them (in PHP/SQL) by student name to see all the classes a student attended. I was thinking about storing the class as a row and the students as an array, but I can't figure out an sql to query the arrays in the db. Am I heading the right direction? Maybe creating a new db row for each student for each class? Maybe making the students rows and update an array of classes for each? I will probably using AJAX later to retrieve the info. Thanks!
Why don't you create two tables to store the information about existing Classes and Students and a relation-table Participant that stores the information about which student goes to which class?
Something along the lines of:
CREATE TABLE Classes (
id int NOT NULL,
description varchar(200),
PRIMARY KEY (id)
)
CREATE TABLE Studentes (
id int NOT NULL,
name varchar(200),
PRIMARY KEY (id)
)
CREATE TABLE Participant (
student_id int NOT NULL,
class_id int NOT NULL,
FOREIGN KEY (student_id) REFERENCES Students(id)
FOREIGN KEY (class_id) REFERENCES Classes(id)
)
Then later, you can find out what classes a students visits with a SQL-query like:
SELECT c.description
FROM Students s
LEFT JOIN Participant p ON (s.id = p.student_id)
LEFT JOIN Classes c ON (p.class_id = c.id)
WHERE s.name = 'SilverSlug'
;
What you are looking for is a relations table. It will keep track of class and students. Example
Classes Table : table of all the classes
ID = Primary key
|ID | Name |
| 1 | Math |
Students Table : table of all the students
ID = Primary key
|ID | Name |
| 1 | Sam |
| 2 | Tom |
Relations Table : Used to keep track of an instance of a class
ID = Primary key Class_ID & Student_ID are Secondary keys
|ID | Class_ID | Student_ID | Time |
| 1 | 1 | 1 | 6am |
| 2 | 1 | 2 | 6am |
With these tables you can make simple queries to find out who's in what class, you can also find out what classes a student has.
So, lets say i have a user table. Each user has the ability to be in a team with upto 3 other users. So for now i have a column for each spot in the team(4 columns total, so your own id fills in a spot so you know where you fit in the team). And i put the ids to the other members of the team in each of the other columns. In the end, everyone on one team would have the same values in those 4 columns.
How would i query sql to look at those ids and pull the info for all the other users on there team (so by looking at one user, i can pull all 4 team members rows)? Is this the most efficient way of storing that data?
Normalize your data from the beginning. It will pay off big time in a long run. This way you'll be able to normally maintain and query your data.
A proposed schema in a simplified form may look like this
CREATE TABLE users
(
`user_id` int not null auto_increment primary key,
`user_name` varchar(5)
);
CREATE TABLE teams
(
`team_id` int not null auto_increment primary key,
`team_name` varchar(5)
);
CREATE TABLE team_users
(
`team_id` int,
`user_id` int,
primary key (team_id, user_id),
foreign key (team_id) references teams (team_id),
foreign key (user_id) references users (user_id)
);
If you need to pull all members for a team with a name 'team2'
SELECT t.team_id, t.team_name, u.user_id, u.user_name
FROM team_users tu JOIN teams t
ON tu.team_id = t.team_id JOIN users u
ON tu.user_id = u.user_id
WHERE t.team_name = 'team2'
If you need to get all members of a team where user with user_id = 2 is a member
SELECT t.team_id, t.team_name, u.user_id, u.user_name
FROM team_users tu JOIN team_users tu2
ON tu.team_id = tu2.team_id JOIN teams t
ON tu.team_id = t.team_id JOIN users u
ON tu.user_id = u.user_id
WHERE tu2.user_id = 2
Sample output:
| TEAM_ID | TEAM_NAME | USER_ID | USER_NAME |
|---------|-----------|---------|-----------|
| 2 | team2 | 2 | user2 |
| 2 | team2 | 4 | user4 |
| 2 | team2 | 5 | user5 |
Here is SQLFiddle demo
I think first of all you should not care about this being the most efficient way of storing such data, but the most logical. MySQL is generally pretty good at being a relational database, so the following should perform extremely well:
Make two tables. One for users (with IDs), one for the teams.
In the team table, you put the 4 IDs of the users. You can put in a team ID and name or whatever if you like, but don't have to.
Then you find the team entry like this:
SELECT * FROM team WHERE u1 == ? OR u2 == ? OR u3 == ? or u4 == ?;
And then you query for the users separately.
To improve performance, you may then think about table joins, joining the user's data onto the team entry:
SELECT * from team
LEFT JOIN user user1 ON u1 == user1.id
LEFT JOIN user user2 ON u2 == user2.id
LEFT JOIN user user3 ON u3 == user3.id
LEFT JOIN user user4 ON u4 == user4.id;
This will fetch you one row per team with all user details in it.
Even better: many to many
A many to many relationship has two tables (users and teams) and a relation table (team_users), that contains pairs of IDs and potential other values (e.g. position on the team).
Then you can map the user to his team, and get all the users (and additional values) from that, all using only the relation table. Using joins, you can again fetch your information along with the mapping, reducing the number of queries. MySQL is really good at this!
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
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