sql JOIN cause double rows - mysql

I have two tables that i need to join them
first table i created using this sql query
CREATE TABLE `users` (
`id` bigint PRIMARY KEY AUTO_INCREMENT,
`user_login` varchar(60),
`user_pass` varchar(255),
`first_name` varchar(30),
`last_name` varchar(30),
`user_status` int(2),
`user_phone_number` varchar(20),
`user_email` varchar(100),
`user_billing_info` text,
`user_temp_units` int(2),
`user_flow_units` int(2),
`user_notes` text
);
second table
CREATE TABLE `station_meta` (
`uid` VARCHAR(25) PRIMARY KEY,
`nickname` varchar(30),
`install_date` date,
`latatude` numeric(10,6),
`longitude` numeric(10,6),
`firmware_ver` varchar(10),
`weir_type` int(2),
`weir_width` numeric,
`dist_to_ground` numeric,
`dist_to_weir` numeric,
`service_fee` numeric,
`notes` text
);
i got double rows when i use this sql query
SELECT * FROM station_meta JOIN users
note: uid is something like 9C9Z454Z5CA in case it need to mention it
so there's not any column that is the same in the other table
UPDATE
Data sample
My results
I'm using it in php function in foreach, so i got double results
Appreciate any help

seems you miss a relation between the two tables ..
if you want avoid cartesian product and retrieve just a matching value between the two table you should add a relation as
table user_station_meta (
`id` bigint PRIMARY KEY AUTO_INCREMENT,
user_id bigint
station_meta_uid VARCHAR(25)
)
once you have inserted the matching values
uid, id
9c2748.. 1
BC8CD4.. 5
you can select single matching result as
select u.*. s.*
from user_station_meta us
JOIN station_meta s on s.uid = us.uid
JOIN users u on u.id = us.id

Related

How do I join two tables from a database in SQL?

I'm currently working on a project where we have to join two tables in SQL and then create a page to show the result of the two tables combined.
This is what I have so far:
SELECT *
FROM
ANIMAL
LEFT OUTER JOIN
FOOD_PORTION
ON
ANIMAL = FOOD_PORTION
and then a second page where the outcome should be:
CREATE TABLE ANIMAL(
AnimalID CHAR(5) PRIMARY KEY,
AnimalName CHAR(50) NOT NULL,
Species CHAR(50) NOT NULL,
Weight INT NOT NULL,
DOB DATE NOT NULL,
ExhibitID CHAR(5) REFERENCES EXHIBIT(ExhibitID)
);
CREATE TABLE FOOD_PORTION(
PortionSize INT NOT NULL,
AnimalID CHAR(5) REFERENCES ANIMAL(AnimalID)
);
SELECT C.Name
FROM ANIMAL AS C
UNION
SELECT S.Name
FROM FOOD_PORTION AS S
This should give you what you need. Using tadman's suggestion to change the char column to INT. Also changing the CHAR to VARCHAR columns.
I also made the ID's in each table Identity columns (so they will auto populate).
CREATE TABLE ANIMAL(
AnimalID INT PRIMARY KEY IDENTITY,
AnimalName VARCHAR(50) NOT NULL,
Species VARCHAR(50) NOT NULL,
Weight INT NOT NULL,
DOB DATE NOT NULL,
ExhibitID CHAR(5) REFERENCES EXHIBIT(ExhibitID)
);
CREATE TABLE FOOD_PORTION(
PortionSize INT IDENTITY,
AnimalID INT REFERENCES ANIMAL(AnimalID)
);
SELECT A.*, FP.*
FROM Animal A
INNER JOIN Food_Portion FP ON A.AnimalID = FP.AnimalID

MYSQL: left Join and sum two tables where one table has two columns referring to the first table

I am trying to create a procedure where my transfer table is joined to my account table. In my transfer table, there are two FK columns that reference the account table id column.
account table:
CREATE TABLE account (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
number VARCHAR(30) NOT NULL DEFAULT '',
description VARCHAR(255)NOT NULL DEFAULT '',
is_active BIT(1) NOT NULL DEFAULT b'1',
PRIMARY KEY (id),
UNIQUE account_name (name, number)
);
transfer table:
CREATE TABLE transfer (
id INT NOT NULL AUTO_INCREMENT,
date DATE NOT NULL,
from_account INT NULL,
to_account INT NULL,
amount DECIMAL(12, 2) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (from_account)
REFERENCES account(id),
FOREIGN KEY (to_account)
REFERENCES account(id)
);
get_account procedure:
CREATE PROCEDURE get_account()
SELECT a.*,
(SUM(t.amount) - SUM(f.amount)) AS balance
FROM account a
LEFT JOIN transfer f
ON a.id = f.from_account
LEFT JOIN transfer t
ON a.id = t.to_account
GROUP BY a.id;
I am trying to subtract the total of the from_accout column from the total of the to_account column. I am able to get the sum of just one column but when I try to get both it returns a NULL.
This seems like it should be easy, but I can't figure it out.

MYSQL Select One Row With Less

I'm making a database for a unit and I need a query that selects the vet with less appointments assigned so I can assign the next appointment to him or her. I don't know how to start, but I'm pretty sure I'll have to use variables here. Those are my tables:
CREATE TABLE IF NOT EXISTS staff (
stafId MEDIUMINT UNSIGNED AUTO_INCREMENT,
stafAdd VARCHAR(150) NOT NULL,
stafConNum VARCHAR(15) NOT NULL,
stafEma VARCHAR(40) NOT NULL,
stafFirNam VARCHAR(20) NOT NULL,
stafLasNam VARCHAR(30) NOT NULL,
stafPos ENUM('nurse', 'vet') NOT NULL,
PRIMARY KEY (stafId)
) engine = InnoDB;
CREATE TABLE IF NOT EXISTS vet (
vetId MEDIUMINT UNSIGNED AUTO_INCREMENT,
FOREIGN KEY (vetId) REFERENCES staff(stafId),
PRIMARY KEY (vetId)
) engine = InnoDB;
CREATE TABLE IF NOT EXISTS appointment (
appoId MEDIUMINT UNSIGNED AUTO_INCREMENT,
appoDat DATETIME NOT NULL,
appoPetId MEDIUMINT UNSIGNED,
FOREIGN KEY (appoPetId) REFERENCES pet(petId),
appoVetId MEDIUMINT UNSIGNED,
FOREIGN KEY (appoVetId) REFERENCES vet(vetId),
PRIMARY KEY (appoId)
) engine = InnoDB;
You should start by looking up the mysql MIN() function. Follow that up with learning about JOINs and you'll be breezing through this.
You could get the vet's with the number of appointment like this:
SELECT
*
FROM
(
SELECT
vet.vetId,
COUNT(*) AS nbrOfAppointment
FROM
vet
JOIN appointment
ON vet.vetId = appointment.appoVetId
) AS tbl
ORDER BY tbl.nbrOfAppointment ASC
This Request gives you the number of appointement per vet ordered by number of appointement.
Select vet.id, count(*) as nb_appointement
from vet
inner join appointement app on vet.vetId = app.appoVetId
group by vet.id
order by nb_appointement asc

SQL select entries in other table linked by foreign keys

I have redesigned my database structure to use PRIMARY and FOREIGN KEYs to link the entries in my 3 tables together, and I am having problems trying to write queries to select data in one table given data in a another table. Here is an example of my 3 CREATE TABLE statements:
CREATE TABLE IF NOT EXISTS players (
id INT(10) NOT NULL AUTO_INCREMENT,
username VARCHAR(16) NOT NULL,
uuid VARCHAR(200) NOT NULL DEFAULT 0,
joined TIMESTAMP DEFAULT 0,
last_seen TIMESTAMP DEFAULT 0,
PRIMARY KEY (id)
);
/* ^
One |
To
| One
v
*/
CREATE TABLE IF NOT EXISTS accounts (
id INT(10) NOT NULL AUTO_INCREMENT,
account_id INT(10) NOT NULL,
pass_hash VARCHAR(200) NOT NULL,
pass_salt VARCHAR(200) NOT NULL,
created BIGINT DEFAULT 0,
last_log_on BIGINT DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (account_id) REFERENCES players(id) ON DELETE CASCADE
) ENGINE=InnoDB;
/* ^
One |
To
| Many
v
*/
CREATE TABLE IF NOT EXISTS purchases (
id INT(10) NOT NULL AUTO_INCREMENT,
account_id INT(10) NOT NULL,
status VARCHAR(20) NOT NULL,
item INT NOT NULL,
price DOUBLE DEFAULT 0,
description VARCHAR(200) NOT NULL,
buyer_name VARCHAR(200) NOT NULL,
buyer_email VARCHAR(200) NOT NULL,
transaction_id VARCHAR(200) NOT NULL,
payment_type VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON DELETE CASCADE
) ENGINE=InnoDB;
Say for example, I want to select all the usernames of users who purchased anything greater than $30. All the usernames are stored in the players table, which is linked to the accounts table and that is linked to the purchases table. Is this this the best way to design this relational database? If so, how would I run queries similar to the above example?
I was able to get get all of a users purchase history given their username, but I did it with 2 sub-queries... Getting that data should be easier than that!
Here is the SELECT query I ran to get all of a players purchase data:
SELECT *
FROM purchases
WHERE account_id = (SELECT id FROM accounts WHERE account_id = (SELECT id FROM players WHERE username = 'username'));
Also, when I try to make references to the other tables using something like 'players.username', I get an error saying that the column doesn't exist...
I appreciate any help! Thanks!
Your design is ok in my opinion. The relation between players and account is one-to-many and not one-to-one since this way, you can have two tuples referencing a single player.
I would write the query you need as:
SELECT DISTINCT p.id, p.username
FROM players p INNER JOIN accounts a ON (p.id = a.account_id)
INNER JOIN purchases pc ON (a.id = pc.account_id)
WHERE (pc.price > 30);
As Sam suggested, I added DISTINCT to avoid repeating id and username in case a user have multiple purchases.
Note the id is here to avoid confusion among repeated usernames.

Selecting a default value if an entry doesn't exist

I have three tables...users, user_info, and quota_levels. They look like this:
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(31) NOT NULL,
password VARCHAR(33) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE user_info (
userID INT UNSIGNED NOT NULL,
firstName VARCHAR(32),
lastName VARCHAR(32),
phone CHAR(14),
address VARCHAR(128),
birthdate DATE,
misc TEXT,
quotaLevel VARCHAR(32),
PRIMARY KEY (userID)
);
CREATE TABLE quota_levels (
quotaLevel VARCHAR(32) NOT NULL,
quota1 INT NOT NULL,
quota2 INT NOT NULL,
PRIMARY KEY (level)
);
Every user will have an entry in the users table, but not necessarily in the user_info table. Each user in the user_info table has a quotaLevel corresponding to the quotaLevel column in the quota_levels table. Possible values for quotaLevel are BRONZE, SILVER, GOLD, and PLATINUM.
I could go into a long explanation of why it is set up this way, but it would be quicker to just say that this structure cannot be changed.
If the user exists, I want to get the quota1 value of their quotaLevel. If the user doesn't exist, the quota1 value for BRONZE should be returned.
I want to do this with ONE query. Can it be done and how?
SELECT u.Name,
COALESCE(ql.quota1, (SELECT quota1 FROM quota_level WHERE quotaLevel = 'BRONZE'))
FROM users u
LEFT JOIN user_info ui
INNER JOIN quota_level ql
ON ui.quotaLevel = ql.quotaLevel
ON u.id = ui.userID