Database design and join operations among database tables - mysql

The theme of this question is to maintain the user comments over my website.
I had around 25000 articles on my website(of different categories) and each article has a comments section below it.Since the number of comments increased over 70,000 I decided to divide the articles into various tables depending on its category articles_of_type_category and a corresponding comments table article_category_comments for each table,assuming that it would improve the performance in future (though currently its working fine)
Now I have two questions :
1) Should I divide the database or there will no degradation in performance if table grows further in size?
2)If yes,then I have some problem in SQL for join operation for the new database design.On the comments page for each article I show the comments,name of the person who made the comment and his points.
So suppose user is viewing the article 3, hence I need to obtain the following detail to show on the page of article 3
-------------------------------------------------------------------------------------------
serial#| comment | name_who_made_this_comment | points | gold | silver | bronze
-------------------------------------------------------------------------------------------
| | | | | |
| | | | | |
by joining these three tables
user_details
+----+--------+----------+
| id | name | college |
+----+--------+----------+
| 1 | naveen | a |
| 2 | rahul | b |
| 3 | dave | c |
| 4 | tom | d |
+----+--------+----------+
score (this table stores the user points like stackoverflow)
+----+--------+------+--------+--------+---------+
| id | points | gold | silver | bronze | user_id |
+----+--------+------+--------+--------+---------+
| 1 | 2354 | 2 | 9 | 25 | 3 |
| 2 | 4562 | 1 | 9 | 11 | 2 |
| 3 | 1123 | 7 | 9 | 11 | 1 |
| 4 | 3457 | 0 | 9 | 4 | 4 |
+----+--------+------+--------+--------+---------+
comments (this table stores comment, id of the article on which it was made,and user id)
+----+----------------------------+-------------+---------+
| id | comment | article_id | user_id |
+----+----------------------------+-------------+---------+
| 1 | This is a nice article | 3 | 1 |
| 2 | This is a tough article | 3 | 4 |
| 3 | This is a good article | 2 | 7 |
| 4 | This is a good article | 1 | 3 |
| 5 | Please update this article | 4 | 4 |
+----+----------------------------+-------------+---------+
I tried something like
select * from comments join (select * from user_details join points where user_details.id=points.user_id)as joined_temp where comments.id=joined_temp.u_id and article_id=3;

This is a response to this comment, "#DanBracuk:It would really be useful if you give an overview by naming the tables and corresponding column names"
Table category
categoryId int not null, autoincrement primary key
category varchar(50)
Sample categories could be "Fairy Tale", "World War I", or "Movie Stars".
Table article
articleId int not null, autoincrement primary key
categoryId int not null foreign key
text clob, or whatever the mysql equivalent is
Since the comment was in response to my comment about articles and categories, this answer is limited to that.

I would start with a table with articles and categories. Then use a bridge table to link the both. My advice would be to index the categories in the bridge table. This would speed up the access.
Example of table structure:
CREATE TABLE Article (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
title varchar(100) NOT NULL
);
INSERT INTO Article
(title)
VALUES
('kljlkjlkjalk'),
('aiouiwiuiuaoijukj');
CREATE TABLE Category (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(100)
);
INSERT INTO Category
(name)
VALUES
('kljlkjlkjalk'),
('aiouiwiuiuaoijukj');
CREATE TABLE Article_Category (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
article_id int,
category_id int
);
INSERT INTO Article_Category
(article_id, category_id)
VALUES
(1,1),
(1,2);
CREATE TABLE User_Details
(`id` int, `name` varchar(6), `college` varchar(1))
;
INSERT INTO User_Details
(`id`, `name`, `college`)
VALUES
(1, 'naveen', 'a'),
(2, 'rahul', 'b'),
(3, 'dave', 'c'),
(4, 'tom', 'd')
;
CREATE TABLE Score
(`id` int, `points` int, `gold` int, `silver` int, `bronze` int, `user_id` int)
;
INSERT INTO Score
(`id`, `points`, `gold`, `silver`, `bronze`, `user_id`)
VALUES
(1, 2354, 2, 9, 25, 3),
(2, 4562, 1, 9, 11, 2),
(3, 1123, 7, 9, 11, 1),
(4, 3457, 0, 9, 4, 4)
;
CREATE TABLE Comment
(`id` int, `comment` varchar(26), `article_id` int, `user_id` int)
;
INSERT INTO Comment
(`id`, `comment`, `article_id`, `user_id`)
VALUES
(1, 'This is a nice article', 3, 1),
(2, 'This is a tough article', 3, 4),
(3, 'This is a good article', 2, 7),
(4, 'This is a good article', 1, 3),
(5, 'Please update this article', 4, 4)
;
Try this:
SQLFiddle Demo
Best of luck.

70000 elements are not so many. In fact the number is close to nothing. Your problem lies in bad design. I have a table with many millions of records and when I request to the application server which executes complex queries in the backend and it responds in less than a second. So you are definitely doing something in sub-optimal design. I think that a detailed answer would take too much space and effort (as we have a complete science built on your question) which is out of scope in this website, so I choose to point you to the right direction:
Read about normalization (1NF, 2NF, 3NF, BCNF and so on) and compare it to your design.
Read about indexing and other implicit optimizations
Optimize your queries and minimize the number of queries
As to answer your concrete question: No, you should not "divide" your table. You should fix the structural errors in your database schema and optimize the algorithms using your database.

Related

Are there sample tables on sqlfiddle

Are there any default tables on SqlFiddle that I can query from?
I want to try a basic analytical query on a simple table but I don't want to set up the schema and seed data etc.
normally I would do something like select * from all_objects
( http://sqlfiddle.com/ )
Auto Shop Database:
SQL fiddle
Library Database:
SQL fiddle
Countries Table:
SQL fiddle
You can use the "View Sample Fiddle" in the SQLFiddle app.
The following content is from "Auto Shop Database" from Stack Overflow Documentation
(archived here); copyright 2017 by FlyingPiMonster, Prateek, forsvarir, Tot Zam, Florin Ghita, Abhilash R Vankayala, WesleyJohnson, Matt, Mureinik, Magisch, Bostjan, Mzzzzzz, Franck Dernoncourt, enrico.bacis, JavaHopper, rdans, bignose, and CL.; licensed
under CC BY-SA 3.0. An archive of the full Stack Overflow
Documentation content can be found at archive.org, in which this
example is indexed by its topic ID: 280, as example: 1014.
Auto Shop Database
In the following example - Database for an auto shop business, we have a list of departments, employees, customers and customer cars. We are using foreign keys to create relationships between the various tables.
Live example: SQL fiddle
Relationships between tables
Each Department may have 0 or more Employees
Each Employee may have 0 or 1 Manager
Each Customer may have 0 or more Cars
Departments
| Id | Name |
|:---|:------|
| 1 | HR |
| 2 | Sales |
| 3 | Tech |
SQL statements to create the table:
CREATE TABLE Departments (
Id INT NOT NULL AUTO_INCREMENT,
Name VARCHAR(25) NOT NULL,
PRIMARY KEY(Id)
);
INSERT INTO Departments
([Id], [Name])
VALUES
(1, 'HR'),
(2, 'Sales'),
(3, 'Tech')
;
Employees
| Id | FName | LName | PhoneNumber | ManagerId | DepartmentId | Salary | HireDate |
|:---|:----------|:---------|:------------|:----------|:-------------|:-------|:-----------|
| 1 | James | Smith | 1234567890 | NULL | 1 | 1000 | 01-01-2002 |
| 2 | John | Johnson | 2468101214 | 1 | 1 | 400 | 23-03-2005 |
| 3 | Michael | Williams | 1357911131 | 1 | 2 | 600 | 12-05-2009 |
| 4 | Johnathon | Smith | 1212121212 | 2 | 1 | 500 | 24-07-2016 |
SQL statements to create the table:
CREATE TABLE Employees (
Id INT NOT NULL AUTO_INCREMENT,
FName VARCHAR(35) NOT NULL,
LName VARCHAR(35) NOT NULL,
PhoneNumber VARCHAR(11),
ManagerId INT,
DepartmentId INT NOT NULL,
Salary INT NOT NULL,
HireDate DATETIME NOT NULL,
PRIMARY KEY(Id),
FOREIGN KEY (ManagerId) REFERENCES Employees(Id),
FOREIGN KEY (DepartmentId) REFERENCES Departments(Id)
);
INSERT INTO Employees
([Id], [FName], [LName], [PhoneNumber], [ManagerId], [DepartmentId], [Salary], [HireDate])
VALUES
(1, 'James', 'Smith', 1234567890, NULL, 1, 1000, '01-01-2002'),
(2, 'John', 'Johnson', 2468101214, '1', 1, 400, '23-03-2005'),
(3, 'Michael', 'Williams', 1357911131, '1', 2, 600, '12-05-2009'),
(4, 'Johnathon', 'Smith', 1212121212, '2', 1, 500, '24-07-2016')
;
Customers
| Id | FName | LName | Email | PhoneNumber | PreferredContact |
|:---|:--------|:-------|:--------------------------|:------------|:-----------------|
| 1 | William | Jones | william.jones#example.com | 3347927472 | PHONE |
| 2 | David | Miller | dmiller#example.net | 2137921892 | EMAIL |
| 3 | Richard | Davis | richard0123#example.com | NULL | EMAIL |
SQL statements to create the table:
CREATE TABLE Customers (
Id INT NOT NULL AUTO_INCREMENT,
FName VARCHAR(35) NOT NULL,
LName VARCHAR(35) NOT NULL,
Email varchar(100) NOT NULL,
PhoneNumber VARCHAR(11),
PreferredContact VARCHAR(5) NOT NULL,
PRIMARY KEY(Id)
);
INSERT INTO Customers
([Id], [FName], [LName], [Email], [PhoneNumber], [PreferredContact])
VALUES
(1, 'William', 'Jones', 'william.jones#example.com', '3347927472', 'PHONE'),
(2, 'David', 'Miller', 'dmiller#example.net', '2137921892', 'EMAIL'),
(3, 'Richard', 'Davis', 'richard0123#example.com', NULL, 'EMAIL')
;
Cars
| Id | CustomerId | EmployeeId | Model | Status | Total Cost |
|:---|:-----------|:-----------|:-------------|:--------|:-----------|
| 1 | 1 | 2 | Ford F-150 | READY | 230 |
| 2 | 1 | 2 | Ford F-150 | READY | 200 |
| 3 | 2 | 1 | Ford Mustang | WAITING | 100 |
| 4 | 3 | 3 | Toyota Prius | WORKING | 1254 |
SQL statements to create the table:
CREATE TABLE Cars (
Id INT NOT NULL AUTO_INCREMENT,
CustomerId INT NOT NULL,
EmployeeId INT NOT NULL,
Model varchar(50) NOT NULL,
Status varchar(25) NOT NULL,
TotalCost INT NOT NULL,
PRIMARY KEY(Id),
FOREIGN KEY (CustomerId) REFERENCES Customers(Id),
FOREIGN KEY (EmployeeId) REFERENCES Employees(Id)
);
INSERT INTO Cars
([Id], [CustomerId], [EmployeeId], [Model], [Status], [TotalCost])
VALUES
('1', '1', '2', 'Ford F-150', 'READY', '230'),
('2', '1', '2', 'Ford F-150', 'READY', '200'),
('3', '2', '1', 'Ford Mustang', 'WAITING', '100'),
('4', '3', '3', 'Toyota Prius', 'WORKING', '1254')
;
The following content is from "Library Database" from Stack Overflow Documentation
(archived here); copyright 2017 by enrico.bacis, Bostjan, Shiva, WesleyJohnson, and Christian; licensed
under CC BY-SA 3.0. An archive of the full Stack Overflow
Documentation content can be found at archive.org, in which this
example is indexed by its topic ID: 280, as example: 1014.
Library Database
In this example database for a library, we have Authors, Books and BooksAuthors tables.
Live example: SQL fiddle
Authors and Books are known as base tables, since they contain column definition and data for the actual entities in the relational model. BooksAuthors is known as the relationship table, since this table defines the relationship between the Books and Authors table.
Relationships between tables
Each author can have 1 or more books
Each book can have 1 or more authors
Authors
(view table)
| Id | Name | Country |
|:---|:---------------------|:--------|
| 1 | J.D. Salinger | USA |
| 2 | F. Scott. Fitzgerald | USA |
| 3 | Jane Austen | UK |
| 4 | Scott Hanselman | USA |
| 5 | Jason N. Gaylord | USA |
| 6 | Pranav Rastogi | India |
| 7 | Todd Miranda | USA |
| 8 | Christian Wenz | USA |
SQL to create the table:
CREATE TABLE Authors (
Id INT NOT NULL AUTO_INCREMENT,
Name VARCHAR(70) NOT NULL,
Country VARCHAR(100) NOT NULL,
PRIMARY KEY(Id)
);
INSERT INTO Authors
(Name, Country)
VALUES
('J.D. Salinger', 'USA'),
('F. Scott. Fitzgerald', 'USA'),
('Jane Austen', 'UK'),
('Scott Hanselman', 'USA'),
('Jason N. Gaylord', 'USA'),
('Pranav Rastogi', 'India'),
('Todd Miranda', 'USA'),
('Christian Wenz', 'USA')
;
Books
(view table)
| Id | Title |
|:---|:--------------------------------------|
| 1 | The Catcher in the Rye |
| 2 | Nine Stories |
| 3 | Franny and Zooey |
| 4 | The Great Gatsby |
| 5 | Tender id the Night |
| 6 | Pride and Prejudice |
| 7 | Professional ASP.NET 4.5 in C# and VB |
SQL to create the table:
CREATE TABLE Books (
Id INT NOT NULL AUTO_INCREMENT,
Title VARCHAR(50) NOT NULL,
PRIMARY KEY(Id)
);
INSERT INTO Books
(Id, Title)
VALUES
(1, 'The Catcher in the Rye'),
(2, 'Nine Stories'),
(3, 'Franny and Zooey'),
(4, 'The Great Gatsby'),
(5, 'Tender id the Night'),
(6, 'Pride and Prejudice'),
(7, 'Professional ASP.NET 4.5 in C# and VB')
;
BooksAuthors
(view table)
| BookId | AuthorId |
|:-------|:---------|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 4 |
| 7 | 5 |
| 7 | 6 |
| 7 | 7 |
| 7 | 8 |
SQL to create the table:
CREATE TABLE BooksAuthors (
AuthorId INT NOT NULL,
BookId INT NOT NULL,
FOREIGN KEY (AuthorId) REFERENCES Authors(Id),
FOREIGN KEY (BookId) REFERENCES Books(Id)
);
INSERT INTO BooksAuthors
(BookId, AuthorId)
VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 3),
(7, 4),
(7, 5),
(7, 6),
(7, 7),
(7, 8)
;
Examples
View all authors (view live example):
SELECT * FROM Authors;
View all book titles (view live example):
SELECT * FROM Books;
View all books and their authors (view live example):
SELECT
ba.AuthorId,
a.Name AuthorName,
ba.BookId,
b.Title BookTitle
FROM BooksAuthors ba
INNER JOIN Authors a ON a.id = ba.authorid
INNER JOIN Books b ON b.id = ba.bookid
;
The following content is from "Countries Table" from Stack Overflow Documentation
(archived here); copyright 2017 by enrico.bacis, Bostjan, and Shiva; licensed
under CC BY-SA 3.0. An archive of the full Stack Overflow
Documentation content can be found at archive.org, in which this
example is indexed by its topic ID: 280, as example: 9933.
Countries Table
In this example, we have a Countries table. A table for countries has many uses, especially in Financial applications involving currencies and exchange rates.
Live example: SQL fiddle
Some Market data software applications like Bloomberg and Reuters require you to give their API either a 2 or 3 character country code along with the currency code. Hence this example table has both the 2-character ISO code column and the 3 character ISO3 code columns.
Countries
(view table)
| Id | ISO | ISO3 | ISONumeric | CountryName | Capital | ContinentCode | CurrencyCode |
|:---|:----|:-----|:-----------|:--------------|:-----------|:--------------|:-------------|
| 1 | AU | AUS | 36 | Australia | Canberra | OC | AUD |
| 2 | DE | DEU | 276 | Germany | Berlin | EU | EUR |
| 2 | IN | IND | 356 | India | New Delhi | AS | INR |
| 3 | LA | LAO | 418 | Laos | Vientiane | AS | LAK |
| 4 | US | USA | 840 | United States | Washington | NA | USD |
| 5 | ZW | ZWE | 716 | Zimbabwe | Harare | AF | ZWL |
SQL to create the table:
CREATE TABLE Countries (
Id INT NOT NULL AUTO_INCREMENT,
ISO VARCHAR(2) NOT NULL,
ISO3 VARCHAR(3) NOT NULL,
ISONumeric INT NOT NULL,
CountryName VARCHAR(64) NOT NULL,
Capital VARCHAR(64) NOT NULL,
ContinentCode VARCHAR(2) NOT NULL,
CurrencyCode VARCHAR(3) NOT NULL,
PRIMARY KEY(Id)
)
;
INSERT INTO Countries
(ISO, ISO3, ISONumeric, CountryName, Capital, ContinentCode, CurrencyCode)
VALUES
('AU', 'AUS', 36, 'Australia', 'Canberra', 'OC', 'AUD'),
('DE', 'DEU', 276, 'Germany', 'Berlin', 'EU', 'EUR'),
('IN', 'IND', 356, 'India', 'New Delhi', 'AS', 'INR'),
('LA', 'LAO', 418, 'Laos', 'Vientiane', 'AS', 'LAK'),
('US', 'USA', 840, 'United States', 'Washington', 'NA', 'USD'),
('ZW', 'ZWE', 716, 'Zimbabwe', 'Harare', 'AF', 'ZWL')
;
For MySQL fiddles, follow the links from the answer by Daniel Käfer.
For Microsoft SQL Server versions of the same tables, use these links:
Auto Shop Database:
SQL fiddle
Library Database:
SQL fiddle
Countries Table:
SQL fiddle

How can I define a specific range for storing values in database?

I want to know, how can I define a limited range (max and min) for storing values in table?
I want this range: [min: -99 , max: 999]
Also here is some example:
CREATE TABLE MyTable(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code INT(11) NOT NULL
)
INSERT INTO MyTable (id,code)
VALUES (1, 42),
VALUES (2, -332),
VALUES (3, -83),
VALUES (4, 44324),
VALUES (5, 0),
VALUES (6, 999);
So, I want this output:
// MyTable
+----+------+
| id | code |
+----+------+
| 1 | 42 |
| 2 | -99 |
| 3 | -83 |
| 4 | 999 |
| 5 | 0 |
| 6 | 999 |
+----+------+
Well, How can I restrict my table for just accepting valid (in range) values or before storing, converts them to max/min value?
Or, If what I considered in above is not possible, Then how can I show the result as valid in range?
// MyTable
+----+------+
| id | code |
+----+------+
| 1 | 42 |
| 2 | -332 |
| 3 | -83 |
| 4 | 44324|
| 5 | 0 |
| 6 | 999 |
+----+------+
I want something like this query:
SELECT id, IF(LENGTH(code) > 999, '999', code)) AS FilteredCode FROM MyTable
// also I can not implement to filter negative values (-99) in my query
You can use the CHECK constraint like this:
CONSTRAINT code_fk CHECK (code BETWEEN -99 AND 999)
So your table will be created as:
CREATE TABLE MyTable(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code INT(11) NOT NULL,
CONSTRAINT code_fk CHECK (code BETWEEN -99 AND 999)
)
See the SQL FIDDLE DEMO
Using check constraint to do this below like:
CREATE TABLE MyTable(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code INT(11) NOT NULL,
CONSTRAINT code_fk CHECK (code BETWEEN -99 AND 999)
)

When to use new table mySql

When should one create a new table in a database and use new ids? Example in a database for tickets for concerts, should I create a new table for each concert then delete it afterwards?
Keeping all the tickets in one database with unique ID's for each does not sound like a scalable solution.
This is a theory question rather than a practical coding question.
Here is a sample example of how you could do this in a relational pattern:
SCHEMA:
Table: USER
+---------------+-------------------+---------------+
| UserID | First Name | Last Name |
+---------------+-------------------+---------------+
| 1 | John | Doe |
|---------------|-------------------|---------------|
| 2 | Jane | Doe |
+---------------+-------------------+---------------+
Table: CONCERT
+---------------+-------------------+-----------+---------------+
| ConcertID | Concert Name | Artist | Date |
+---------------+-------------------+-----------+---------------+
| 1 | Rock Concert | Rob | Jan-1-2014 |
|---------------|-------------------|-----------|---------------|
| 2 | Rap Concert | Jay | Feb-3-2014 |
+---------------+-------------------+-----------+---------------+
Table: TICKET
+-----------+---------------+---------------+
| UserID | ConcertID | Quantity |
+-----------+---------------+---------------+
| 1 | 1 | 1 |
|-----------|---------------|---------------|
| 1 | 2 | 3 |
|-----------|---------------|---------------|
| 2 | 1 | 2 |
+-----------+---------------+---------------+
Raw SQL to create above schema:
CREATE TABLE USER (
`UserID` int unsigned primary key,
`First Name` varchar(4) not null,
`Last Name` varchar(3) not null
) engine=innodb charset=utf8;
INSERT INTO USER
(`UserID`, `First Name`, `Last Name`)
VALUES
(1, 'John', 'Doe'),
(2, 'Jane', 'Doe')
;
CREATE TABLE CONCERT (
`ConcertID` int unsigned primary key,
`Concert Name` varchar(12) not null,
`Artist` varchar(3) not null,
`Date` datetime not null
) engine=innodb charset=utf8;
INSERT INTO CONCERT
(`ConcertID`, `Concert Name`, `Artist`, `Date`)
VALUES
(1, 'Rock Concert', 'Rob', '2014-01-01 00:00:00'),
(2, 'Rap Concert', 'Jay', '2014-02-03 00:00:00')
;
CREATE TABLE TICKET (
`Ticket No` int unsigned primary key auto_increment,
`UserID` int unsigned,
`ConcertID` int unsigned,
Foreign Key(`UserID`) references `USER`(`UserID`),
Foreign Key(`ConcertID`) references `CONCERT`(`ConcertID`)
) engine=innodb charset=utf8;
INSERT INTO TICKET
(`Ticket No`, `UserID`, `ConcertID`)
VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 1)
;
You need to break apart your tables in such a way that you have one-to-one or one-to-many relationships without having a many-to-many relationship. By using a simple three table setup as described above, one user can purchase multiple tickets to multiple concerts. However, because of the itermediary table TICKET, we are never left with a many-to-many relationship. This also allows us to maintain referential integrity by tying the UserID in the TICKET table to the UserID in the USER table. In addtion, the ConcertID in the TICKET table to the ConcertID in the CONCERT table.
Finally, we are able to generate some simple queries to pull back information we need by joining the tables together. I've included two sample queries below:
SAMPLE QUERY #1 - Retrieve all tickets of a particular user by first and last name
SELECT
`conc`.`Concert Name`,
`conc`.`Artist`,
`conc`.`Date`,
`tick`.`Ticket No`
FROM `CONCERT` AS `conc`
INNER JOIN `TICKET` AS `tick` ON `conc`.`ConcertID` = `tick`.`ConcertID`
INNER JOIN `USER` AS `user` ON `tick`.`UserID` = `user`.`UserID`
WHERE `user`.`First Name` = "John" AND `user`.`Last Name` = "Doe";
Result:
+--------------------+--------------+---------------------------------+-----------------+
| Concert Name | Artist | Date | Ticket No |
+--------------------+--------------+---------------------------------+-----------------+
| Rock Concert | Rob | January, 01 2014 00:00:00+0000 | 1 |
|--------------------|--------------|---------------------------------|-----------------|
| Rap Concert | Jay | February, 03 2014 00:00:00+0000 | 2 |
+--------------------+--------------+---------------------------------+-----------------+
SAMPLE QUERY #2 - Retrieve total number of tickets for a given concert by artist name
SELECT
COUNT(`tick`.`Ticket No`)
FROM `TICKET` as `tick`
INNER JOIN `CONCERT` AS `conc` ON `tick`.`ConcertID` = `conc`.`ConcertID`
WHERE `conc`.`Artist` = "Rob";
Result:
+--------------------+
| Ticket Count |
+--------------------+
| 2 |
+--------------------+
As an extra note, because we are using foreign key constraints, we have indexes defined on the particular columns. This helps SQL better manage and scale the queries/data leading to continued performance even with large numbers (millions) of rows.
Hope this helps. From here, you should be able to develop a lot of different queries to pull back all the information you desire. An exact working demo of the above code can be found below:
DEMO: sqlfiddle.com
A compromise solution to this would be to create a new table in the same database for each concert, and to delete tables if there are space concerns. This would allow you to keep old data around without cluttering one table too much.

Automating table normalization

I have a table with this structure (simplified):
artID: 1
artName: TNT
ArtBrand: ACME
...
And I want to normalize it making a separate table for the brand (it will have additional data about every brand)
So I want to end up with this
article table:
artID: 1
artName: TNT
brandID: 1
...
brand table
brandID: 1
brandName: ACME
brandInfo: xyz
....
This table have way too many brands to do this manually.
Any easy way to automate this?
I'm using MySQL
As the other answers suggested, you can use the INSERT ... SELECT syntax to do something like this:
INSERT INTO brands (brandName)
SELECT artBrand
FROM original
GROUP BY artBrand;
INSERT INTO articles (artName, brandID)
SELECT o.artName, b.brandID
FROM original o
JOIN brands b ON (b.brandName = o.artBrand);
Test case:
CREATE TABLE original (artID int, artName varchar(10), artBrand varchar(10));
CREATE TABLE articles (artID int auto_increment primary key, artName varchar(10), brandID int);
CREATE TABLE brands (brandID int auto_increment primary key, brandName varchar(10));
INSERT INTO original VALUES (1, 'TNT1', 'ACME1');
INSERT INTO original VALUES (2, 'TNT2', 'ACME1');
INSERT INTO original VALUES (3, 'TNT3', 'ACME1');
INSERT INTO original VALUES (4, 'TNT4', 'ACME2');
INSERT INTO original VALUES (5, 'TNT5', 'ACME2');
INSERT INTO original VALUES (6, 'TNT6', 'ACME3');
INSERT INTO original VALUES (7, 'TNT7', 'ACME3');
INSERT INTO original VALUES (8, 'TNT8', 'ACME3');
INSERT INTO original VALUES (9, 'TNT9', 'ACME4');
Result:
SELECT * FROM brands;
+---------+-----------+
| brandID | brandName |
+---------+-----------+
| 1 | ACME1 |
| 2 | ACME2 |
| 3 | ACME3 |
| 4 | ACME4 |
+---------+-----------+
4 rows in set (0.00 sec)
ELECT * FROM articles;
+-------+---------+---------+
| artID | artName | brandID |
+-------+---------+---------+
| 1 | TNT1 | 1 |
| 2 | TNT2 | 1 |
| 3 | TNT3 | 1 |
| 4 | TNT4 | 2 |
| 5 | TNT5 | 2 |
| 6 | TNT6 | 3 |
| 7 | TNT7 | 3 |
| 8 | TNT8 | 3 |
| 9 | TNT9 | 4 |
+-------+---------+---------+
9 rows in set (0.00 sec)
I would use create table as select
... syntax to create the brands
table with generated id-s
create the brand_id column, and fill it up with the generated id-s from the brands table, using the existing brand columns in article table.
remove the brand columns from article table except of course brand_id
create the foreign key...
Generating brands table should be fairly simple:
CREATE TABLE brands (
id INT PRIMARY KEY AUTO_INCREMENT,
brand_name VARCHAR(50),
brand_info VARCHAR(200)
);
INSERT INTO brands VALUES (brand_name)
SELECT ArtBrand FROM Table
GROUP BY ArtBrand;
Similar story with creating relations between your original table and new brands table, just that select statement in your insert will look like this:
SELECT t.artId, b.id
FROM table t JOIN brands b ON (t.ArtBrand = b.brand_name)

mysql GROUP_CONCAT

I want to list all users with their corropsonding user class.
Here are simplified versions of my tables
CREATE TABLE users (
user_id INT NOT NULL AUTO_INCREMENT,
user_class VARCHAR(100),
PRIMARY KEY (user_id)
);
INSERT INTO users VALUES
(1, '1'),
(2, '2'),
(3, '1,2');
CREATE TABLE classes (
class_id INT NOT NULL AUTO_INCREMENT,
class_name VARCHAR(100),
PRIMARY KEY (class_id)
);
INSERT INTO classes VALUES
(1, 'Class 1'),
(2, 'Class 2');
And this is the query statement I am trying to use but is only returning the first matching user class and not a concatenated list as hoped.
SELECT user_id, GROUP_CONCAT(DISTINCT class_name SEPARATOR ",") AS class_name
FROM users, classes
WHERE user_class IN (class_id)
GROUP BY user_id;
Actual Output
+---------+------------+
| user_id | class_name |
+---------+------------+
| 1 | Class 1 |
| 2 | Class 2 |
| 3 | Class 1 |
+---------+------------+
Wanted Output
+---------+---------------------+
| user_id | class_name |
+---------+---------------------+
| 1 | Class 1 |
| 2 | Class 2 |
| 3 | Class 1, Class 2 |
+---------+---------------------+
Thanks in advance
This is not the best design, but here's the query you want:
SELECT user_id, GROUP_CONCAT(class_name)
FROM users
JOIN classes
ON FIND_IN_SET(class_id, user_class)
GROUP BY
user_id
This breaks rules of database normalization. Don't store many-to-many values in a comma-separated list. Instead make another table user_classes with fields user_id and class_id. This table is simply used as a link table between the other two classes. After this you can use GROUP_CONCAT to do what you want.