Select the oldest from join - mysql

I'm making my own archive system. Here is how it looks so far. I have following SQL tables:
CREATE TABLE items (
id int NOT NULL AUTO_INCREMENT,
serial_number varchar(255) NOT NULL,
catalog_number varchar(255) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE entities (
id int NOT NULL AUTO_INCREMENT,
table_name varchar(255) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE entities_relations (
id int NOT NULL AUTO_INCREMENT,
table_name varchar(255) NOT NULL,
entity_id int NOT NULL,
row_id int NOT NULL,
PRIMARY KEY (id)
);
Each entity where table_name is "items" has at least one item matched via entities_relations. entities_relations shows how many relations are between one entity and items. After saving an item it saves a new Item which is a copy of the previous one and adds a relation. Copies (archive items) don't create a new entity, they create only relation. The oldest relation is the original item.
The following SQL syntax shows me items list. It's wrong because it shows me all items, even if they are archived. I would like to display only the original ones. How can I change it to be able to display only original ones and ignore archives?
SELECT
items.*,
FROM
items
LEFT JOIN entities_relations ON
entities_relations.row_id = items.id
LEFT JOIN entities ON
entities.id = entities_relations.entity_id
WHERE
entities.name = 'items'
ORDER BY
entities.id DESC,
entities_relations.entity_id DESC
LIMIT 0, 50

Related

using join to get records of a specific fk

I have a table of ParentsSchoolContact, which a parentId have foreign key to the parentId:
CREATE TABLE ParentsSchoolContact (
contactId int NOT NULL AUTO_INCREMENT,
parentId int NOT NULL,
name varchar(60) NOT NULL,
age varchar(60) NOT NULL,
PRIMARY KEY (contactId),
FOREIGN KEY (parentId) REFERENCES Parent(parentId)
);
and I have a parent and contact table that keeps the relation between a kid and a parent:
CREATE TABLE ParentAndContact (
parentId int NOT NULL,
contactId int NOT NULL,
PRIMARY KEY (contactId, parentId)
);
I want to get all the contacts related to a specific parent that i have its id, would that be the right query?
SELECT c.name, c.age
FROM ParentsSchoolContact c
INNER JOIN ParentAndKid pc ON pc.contactId = c.contactId
AND c.parentId = myParentVariable
AND pc.parentId = myParentVariable
wanted to make sure this query dosent fall in some case you could think about :)
thanks!
For me, i see that the ParentAndContact table is redundant. Usually the Parents details are in one table and ContactID/Kids details are in another table (having attributes eg. courses which the kids enrolled, details of the kids).
Assuming that you want to get all the contacts related to a specific parent that you have its id from the available tables (ParentsSchoolContact,ParentAndContact), You can just write a simple query to retrieve the information from ParentsSchoolContact table as of below:-
select contactId, parentId, name, age
from ParentsSchoolContact
where parentId = myParentVariable
Do let me know if i miss out anything.

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.

Sort the order of "ORDER BY" query

I need to somehow order the ORDER BY column by using another table's order.
Table that contains sort:
CREATE TABLE IF NOT EXISTS `menu_category` (
`CATEGORY_ID` int(11) NOT NULL AUTO_INCREMENT,
`CATEGORY_NAME` varchar(20) NOT NULL,
`BUTTON_SORT` int(11) DEFAULT NULL,
PRIMARY KEY (`CATEGORY_ID`),
UNIQUE KEY `CATEGORY_NAME` (`CATEGORY_NAME`),
);
Keep in mind that BUTTON_SORT can be null.
Table that needs grouping:
CREATE TABLE IF NOT EXISTS `ticket_item` (
`TICKET_ITEM_ID` int(11) NOT NULL AUTO_INCREMENT,
`TICKET_ITEM_DESC` varchar(30) NOT NULL,
`TICKET_PRINT_CAT` varchar(40) NOT NULL,
PRIMARY KEY (`TICKET_ITEM_ID`),
);
I currently use this query:
SELECT
TICKET_ITEM_ID,
TICKET_ITEM_DESC
FROM ticket_item
WHERE
ticket_item.TICKET_ID = 1
GROUP BY TICKET_PRINT_CAT
What this ends up doing is that it will group everything correctly, but the order of which it is printed is just alphabetical. I need to sort the groups by order of BUTTON_SORT instead. I have no idea where to start for this.
EDIT: I apologize, TICKET_PRINT_CAT and CATEGORY_NAME are relative.
SELECT
TICKET_ITEM_ID,
TICKET_ITEM_DESC
FROM ticket_item
INNER JOIN menu_category ON menu_category.CATEGORY_NAME=ticket_item.TICKET_PRINT_CAT
WHERE
ticket_item.TICKET_ID = 1
GROUP BY TICKET_PRINT_CAT
ORDER BY menu_category.BUTTON_SORT
You need to use joins here. This creates a result set that can have values from both tables, and also can be ordered or grouped by values from either table.
SELECT
ticket_item.TICKET_ITEM_ID, ticket_item.TICKET_ITEM_DESC
FROM ticket_item
LEFT JOIN table2 on ticket_item.someColumnOnTable1 = table2.someColumnOnTable2
ORDER BY table2.whateverColumnYouWantToOrderBy

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.

Why do I get the errors ambiguous field or unknown column in field list?

I created these two tables:
CREATE TABLE `Game` (
`GameName` varchar(30) NOT NULL,
`GameGenre` varchar(20) NOT NULL,
`GameDescription` varchar(500) NOT NULL,
`GameMode` varchar(20) NOT NULL,
PRIMARY KEY (`GameName`)
) ENGINE=InnoDB;
CREATE TABLE `GameScoreTotal` (
`ScoreID` int(3) NOT NULL AUTO_INCREMENT,
`GameName` varchar(30) NOT NULL,
`OverallScoreTotal` mediumint(9) NOT NULL,
`GraphicsTotal` mediumint(9) NOT NULL,
`StoryTotal` mediumint(9) NOT NULL,
`GameplayTotal` mediumint(9) NOT NULL,
`TimeTotal` mediumint(9) NOT NULL,
PRIMARY KEY (`ScoreID`),
CONSTRAINT FOREIGN KEY (`GameName`) REFERENCES `Game` (`GameName`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
My query needs to return all information from game table for the top ten games based on GameScoreTotal.OverallScoreTotal.
Queries I have tried:
SELECT GameName
FROM Game
FULL JOIN GameScoreTotal
ON Game.GameName=GameScoreTotal.GameName
ORDER BY OverallScoreTotal DESC
LIMIT 0, 10;
SELECT Game.GameName
FROM Game
FULL JOIN GameScoreTotal
ON Game.GameName=GameScoreTotal.GameName
ORDER BY OverallScoreTotal DESC
LIMIT 0, 10;
Both tables have legitimate records within them.
Query 1
In your first query, the issue is that the field GameName exist in both the tables Game and GameScoreTotal. Hence the error Column 'GameName' in field list is ambiguous
Query 2
MySQL doesn't have a FULL JOIN. Read here about MySQL JOIN Syntax.
Try the LEFT OUTER JOIN between Game and GameScoreTotal table, this join will fetch all records from Game table and all the matching records from GameScoreTotal table, if there are no matching records in GameScoreTotal table, NULL will be displayed.
You can also try INNER JOIN, which will fetch only the matching records between the two tables.
Script:
SELECT Game.GameName
FROM Game
LEFT OUTER JOIN GameScoreTotal
ON Game.GameName=GameScoreTotal.GameName
ORDER BY OverallScoreTotal DESC
LIMIT 0, 10;