I have a event in which I am storing a string in a variable. Now I want to use that variable to create a new table. Everytime my event runs it creates table with the name of "mon". What is I am doing wrong ?
BEGIN
DECLARE onlyweek INT;
DECLARE mon VARCHAR(20);
SET #mon = "rehan";
CREATE TABLE mon(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
capacity INT NOT NULL
);
END
Because you use mon instead of #mon. And even then it wont work because you need dynamic SQL for that.
But what is even more important:
Don't do that!
Don't create a table on the fly. Table designs should be static. That smells like a big design flaw.
This is a design mistake. For example, you need to make report for the year. In your design you have to join 12 tables and where-s how to join. And this is very slow.
Better design is creating 2 tables - "months" and "reporting_periods" with foreign key to table 'months'. This way when you need year report - you join only 2 tables by ID with "where".
Table 'months' can be filled once a year using same mysql events.
Then use mysql "stored procedure" (and mysql event) for periodic insert into reporting_period with month id. Months` names can include year as "bad way" or have the field 'year' = 'better one'.
CREATE TABLE months(
id int auto_increment,
name varchar(10),
number int not null,
year int not null,
constraint monthes_pk
primary key (id)
);
and reporting_period
CREATE TABLE reporting_period(
id INT auto_increment,
period_id INT NOT NOT,
capacity INT NOT NULL,
constraint `reporting_period_pk`
primary key (id),
constraint `reporting_period__fk`
foreign key (period_id) references months (id)
);
More about DB design: normalization
Related
lets say I have an account object in my application, which currently represented as:
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (accountId)
);
Now, Account object need to also have Solution field...and Status have 4 different possible values:
Solution1, Solution2, Solution3, Solution4
What would be the right way to represent it in the database?
Account can have few statuses, and status can have few accounts...
So at first I thought create in the db table of Solutions and than have another table to hold the relationship, but its seems too complicated for a field that have only 4 possible values...
Create a junction table to represent the relationships between accounts and solutions:
CREATE TABLE account_solution (
accountId int NOT NULL,
solutionId int NOT NULL
PRIMARY KEY (accountId, solutionId)
)
For your solution table, since there are only 4 values, you might be able to take advantage of MySQL's enum type, e.g.
CREATE TABLE solution
solutionId int NOT NULL PRIMARY KEY,
status ENUM('Solution1', 'Solution2', 'Solution3', 'Solution4')
);
You can use set Mysql SET type
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
status set('Solution1','Solution2','Solution3','Solution4') NOT NULL,
PRIMARY KEY (accountId)
);
And if you want to select a specific status
SELECT *
FROM `Account`
WHERE FIND_IN_SET( 'Solution2', `status` ) >0
There is a factory with 15 production lines. Each production line, every day gets its own table and needs to fill in efficiency measurements every hour. Table consists of columns (time periods) and categories with sub categories which makes it around 80 rows. Here is an example:
Could you give me any suggestions with database design ?
Requirements:
Server needs to get all table data for specific day fast.
Server needs to retrieve a specific cell (by line number, date, time period and subcategory) fast.
create table metric
( -- a thing to track
metricNum int auto_increment primary key, -- 1,2,3 etc
metricName varchar(200) -- ie: "Splat & spild", etc
);
create table efficiency
( -- all data for all lines for all time
id int auto_increment primary key,
lineNum int not null,
theDate day not null,
metricNum int not null,
theHour int not null,
theCount int not null
-- add indexes of use
-- add foreign key (FK) constraint(s), such as to metric
);
That's it. Two tables. Not each line with a new table each day.
So I'm new to the use of multiple tables. Prior to today, 1 table suited my needs (and I could probably get away with using 1 here as well).
I'm creating a plugin for a game I play but I'm using a MySQL database to store all the information. I have 3 tables, Players, Warners and Warns. Warns has 2 foreign keys in it (one referencing to Players and the other to Warners).
At the moment I need to do 3 queries. Add the information to Players & Warners, and then to Warns. Is there a way I can cut down the amount of queries and what would happen if I were to just omit the first 2 queries?
Query Examples:
INSERT INTO slimewarnsplayers VALUES ('123e4567-e89b-12d3-a456-426655440000', 'Spedwards');
INSERT INTO slimewarnswarners VALUES ('f47ac10b-58cc-4372-a567-0e02b2c3d479', '_Sped');
INSERT INTO slimewarnswarns VALUES ('', '123e4567-e89b-12d3-a456-426655440000', 'f47ac10b-58cc-4372-a567-0e02b2c3d479', 'spamming', 'medium');
Tables:
CREATE TABLE IF NOT EXISTS SlimeWarnsPlayers (
uuid VARCHAR(36) NOT NULL,
name VARCHAR(26) NOT NULL,
PRIMARY KEY (uuid)
);
CREATE TABLE IF NOT EXISTS SlimeWarnsWarners (
uuid VARCHAR(36) NOT NULL,
name VARCHAR(26) NOT NULL,
PRIMARY KEY (uuid)
);
CREATE TABLE IF NOT EXISTS SlimeWarnsWarns (
id INT NOT NULL AUTO_INCREMENT,
pUUID VARCHAR(36) NOT NULL,
wUUID VARCHAR(36) NOT NULL,
warning VARCHAR(60) NOT NULL,
level VARCHAR(60) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (pUUID) REFERENCES SlimeWarnsPlayers(uuid),
FOREIGN KEY (wUUID) REFERENCES SlimeWarnsWarners(uuid)
);
Is there a way I can cut down the amount of queries?
NO, I don't see that. From your posted INSERT statements (as depicted below) it's clear that those are 3 different tables and you are inserting different data to them. so, you will have to perform the INSERT operation separately for them.
INSERT INTO slimewarnsplayers
INSERT INTO slimewarnswarners
INSERT INTO slimewarnswarns
Another option would be (May not be considered good), creating a procedure which will accept the data and table name and create a prepared statement/dynamic query to achieve what you are saying. something like (A sample pseudo code)
create procedure sp_insert(tablename varchar(10), data1 varchar(10),
data2 varchar(10))
as
begin
--dynamic query here
INSERT INTO tablename VALUES (data1, data2);
end
To explain further, you can then call this procedure from your application end passing the required data. Do note that, if you have a Foreign Key relationship with other table then you will have to catch the last inserted key from your master table and then pass the same to procedure.
No, you can't insert into multiple tables in one MySQL command. You can however use transactions.
BEGIN;
INSERT INTO slimewarnsplayers VALUES(.....);
last_id = LAST_INSERT_ID()
INSERT INTO SlimeWarnsWarners VALUES(last_id, ....);
INSERT INTO SlimeWarnsWarns VALUES(last_id, ....);
COMMIT;
I would also take a look at http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
and this post MySQL Insert into multiple tables? (Database normalization?)
I have a preexisting sqlserver table. Among other fields it has an identity column called as ID which is also a primary key and a RecordNumber column which is a required field. The int value in the RecordNumber column has to be unique. So before inserting a row, I get the max value of the ID column, add 1 to it and then inserting the row with the RecordNumber field = ID + 1. The problem is when two users try to save at the same time, they may get the same ID value and hence will save the same value in the RecordNumber field. Please let me know how to resolve this.
Thanks
The simplest and most efficient way to do this is to define that column as *auto increment *
refer
http://www.w3schools.com/sql/sql_autoincrement.asp
You can use the Transaction concept, using Commit and Rollback operations.
Very interesting link on MSDN : http://msdn.microsoft.com/en-gb/library/ms190295.aspx
Alternative #1 - Auto Increment a Field
CREATE TABLE SampleTable
(
P_Id int NOT NULL Identity(1,1),
FirstName varchar(255),
PRIMARY KEY (P_Id)
)
Alternative #2 - SequentialID as Default Constraint
CREATE TABLE SampleTable
(
P_Id uniqueidentifier NOT NULL,
FirstName varchar(255),
PRIMARY KEY (P_Id)
)
ALTER TABLE [dbo].[SampleTable]
ADD CONSTRAINT [DF_SampleTable_P_Id]
DEFAULT newsequentialid() FOR [P_Id]
Alternative #3 - NewID as Default Constraint
CREATE TABLE SampleTable
(
P_Id Varchar(100) NOT NULL,
FirstName varchar(255),
PRIMARY KEY (P_Id)
)
ALTER TABLE [dbo].[SampleTable]
ADD CONSTRAINT [DF_SampleTable_P_Id]
DEFAULT (newid()) FOR [P_Id]
Sample recommended Stored Proc should be used in case of Muti User Transaction
BEGIN TRY
SET NOCOUNT ON
SET XACT_ABORT ON
Begin TRAN
--Your Code
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
END CATCH
I imagine that I have designed my database badly, but I'm currently stumped by the fact that I need to use dynamic sql in a trigger and that's making mysql unhappy.
The context is that I have created a membership database with several dozen tables, the main one of which is the 'member' table with a unique primary key 'id'. There are a number of other tables which have foreign keys referring to the member.id field.
Because the data has been gathered over many years and with little dupe-control, there is another field in the 'member' table called 'superseded_by', which contains the id of the member who supersedes this one. By default, superseded_by is set to be the member_id. Any one whose superseded_by <> id is deemed to be a dupe.
Now the tricky part... when we identify a dupe, we want to set the superseded_by field to point to the new primary member and update all the tables with foreign keys pointing to the now redundant member id. I have tried to do this using an after update trigger... and then I've tried to be clever by querying the foreign keys from the information_schema and using dynamic sql to update them.
This clearly doesn't work (Error Code: 1336 Dynamic SQL is not allowed in stored function or trigger).
I'm assuming there is a better way to design the schema / handle dupes which I haven't thought of.
Help please...
CODE SNIPPET:
-- ---
-- Table 'member'
-- ---
DROP TABLE IF EXISTS member;
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
superseded_by INTEGER DEFAULT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (mailing_address_id) REFERENCES mailing_address (id),
FOREIGN KEY (superseded_by) REFERENCES member (id)
);
DELIMITER $$
CREATE TRIGGER set_superseded_by_on_insert BEFORE INSERT ON member FOR EACH ROW
BEGIN
SET NEW.superseded_by = NEW.id;
END$$
-- Trigger to update other tables (volunteers, donations, presenters, etc.) when member's superseded_by record is updated
-- Assumes the new superseding person exists (they should also not be superseded by anyone themselves)
CREATE TRIGGER adjust_foreign_member_keys_on_superseded_by_update AFTER UPDATE ON member FOR EACH ROW
BEGIN
DECLARE db, tbl, col VARCHAR(64);
DECLARE fk_update_statement VARCHAR(200);
DECLARE no_more_rows BOOLEAN;
DECLARE fks CURSOR FOR SELECT kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.COLUMN_NAME
FROM information_schema.TABLE_CONSTRAINTS tc
JOIN information_schema.KEY_COLUMN_USAGE kcu ON
tc.table_schema = kcu.table_schema AND tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type='FOREIGN KEY' AND
kcu.REFERENCED_TABLE_NAME = 'member' AND
kcu.REFERENCED_COLUMN_NAME = 'id';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
IF NEW.superseded_by <> OLD.superseded_by THEN
OPEN fks;
SET no_more_rows = FALSE;
update_loop: LOOP
FETCH fks INTO db, tbl, col;
IF no_more_rows THEN
LEAVE update_loop;
END IF;
SET #fk_update_statement = CONCAT("UPDATE ", db, ".", tbl, " SET ", col, " = NEW.superseded_by WHERE ", col, " = NEW.id;");
PREPARE stmt FROM #fk_update_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE fks;
END IF;
END$$
DELIMITER ;
Why are you trying to maintain duplicates in your main table? Seems like you'd be better off with a member table and a member_history table to track previous changes. You could do it by having a table that stored the field changed, date changed and the old and new values. Or you could just store the previous snapshot of the member table before updating it. For instance:
INSERT INTO member_history SELECT NULL, * FROM member WHERE id = ?
UPDATE member SET [...] WHERE id = ?
The schema for member_history would be nearly identical except that you would store member.id as member_id and have a separate primary key for each history entry. (Note: I'm glossing over the syntax a little, the NULL, * part might not work in which case you may need to explicitly name all the fields. Haven't taken the time to check it).
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (mailing_address_id) REFERENCES mailing_address (id),
);
CREATE TABLE member_history (
id INTEGER AUTO_INCREMENT,
member_id INTEGER NOT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (member_id) REFERENCES member (id),
);
Notice that I removed the superseded_by field in the member table and the foreign key to mailing_address in the member_history table. You shouldn't need the superseded_by any more and keeping the foreign key in the member_history table isn't really necessary unless you're worried about dangling references in your history.
Ok, just a couple of thoughts on this:
superseded_by is referencing id on the same table and is in general equal to the latter - not in those cases where you were able to identify a dupe, though, in which case it would point to another already existing member's id.
Given that we can safely assume that no superseded_by field will ever hurt the foreign key constraint.
I further assume that id and superseded_by fields of dupes that have not been identified yet are equal.
So, if all of the above is true, you may bend the foreign key of the other related tables to reference superseded_by instead of id. This way you could cascade the changes made to the dupe down to the other tables and still have the exact same constraint as before.
What you think? Am I missing something?
Please note that this is an option only if you are using InnoDB rather than MyISAM.
Regards,
aefxx
Trigger and stored function in mysql have limitations that we can not use dynamic sql in both of these. I hope this helps.