Let's say that I have the following tables:
Elements:
(int) ID
(int) Name_id
Names:
(int) ID
(varchar) Name
The Elements.Name_id has an internal relation with Names.id. The user enters an element name in a html form. Then a php script inserts the element name to the Elements table. And here comes my question:
Is it possible to specify the element name instead of the element name_id in the insert query? If not I will have to:
SELECT `ID` FROM `Names` WHERE `Names`.`Name` LIKE "$php_variable";
...
INSERT INTO `Elements` SET `Name` = "$php_variable";
Of course the second $php_variable is a result from the previous query.
You can just do:
insert into elements(name)
select n.name
from names n
where n.id = $php_variable;
Now, having said this, do not take this approach. Your data structure is wrong. You want to connect to names.id, not names.name, in most cases. (There are some exceptions where copying the name might be one solution for a slowly changing dimension, but I doubt that is your use-case.)
So, fix the data structure. The create table statements would look like:
create table names (
name_id int auto_increment primary key,
name varchar(255) unique
);
create table elements (
element_id int auto_increment primary key,
name_id int,
foreign key (name_id) references names(name_id)
);
Then use an explicit JOIN to get the name when you need it.
Note: I changed the ids of the table to be "tablename_Id". This is not required, but I find it helpful to have foreign keys and primary keys have the same names.
Related
how do I add a column with type array using phpMyAdmin
knowing that
alter table name add column listid integer array;
alter table name add column listid integer [];
not working
As mentioned in the comments, an array is not a type. You could opt to instead have a separate table which keeps the elements in the array, and let them have a foreign key referring to the original table, or parse the array into a String each time and store it as text, depending on your needs.
CREATE TABLE orders (
id INT NOT NULL PRIMARY KEY,
description TEXT,
reference TEXT
-- This is where you'd want to add your list of order lines
);
-- Instead, we'll create an orderline table referring back to the orders
CREATE TABLE orderlines (
id INT NOT NULL PRIMARY KEY,
description TEXT,
order_id INT REFERENCES orders(id)
);
Now you can put your array values (which I now assume to be the order lines) in their own separate table. To query them, you could do
SELECT * FROM orders
LEFT JOIN orderlines ON orderlines.order_id = orders.id;
Which you could probably make smart enough using sub-queries to return you an array, especially within your application.
So I have a few tables in a database setup and I'm wondering what the best way to do something is.
Essentially I have a 1-to-many relationship where a single user can "own" multiple items, which is represented by an array in php, which will likely return the unique item number, type, and values of the item. How would I go about storing that in a MySql table?
Would it be best to have a lookup table of every single item along with it's ID and present owner? Would it make more sense to put a line item in the user table that had a csv list of every item owned by every player (that would be a nightmare to index?)
What makes sense here?
Example:
class character contains items[]
character 1 has the following entries in his items list:
1, 2, 5, 10,11,12
character 2 has the following entries in his items list:
3,4,6,7,8,9,13
What would be a decent way to store this data?
Thanks,
Never, ever store delimited string values in a database. Normalize your data by creating a many-to-many table instead. That way you'll be able to normally query your data.
That being said your schema might look like
CREATE TABLE characters
(
char_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(32),
...
) ENGINE = InnoDB;
CREATE TABLE items
(
item_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(6),
...
) ENGINE = InnoDB;
CREATE TABLE item_list
(
char_id INT NOT NULL,
item_id INT NOT NULL,
PRIMARY KEY (char_id, item_id),
FOREIGN KEY (char_id) REFERENCES characters (char_id),
FOREIGN KEY (item_id) REFERENCES items (item_id)
) ENGINE = InnoDB;
If you later need to produce a delimited list of items per character so that you can then explode this values while you iterating over the resultset you can use a query like this
SELECT char_id, GROUP_CONCAT(item_id) items
FROM item_list
-- WHERE ...
GROUP BY char_id
Here is SQLFiddle demo
Is it possible to create auto-increment based on a specific field? For example i have UserId and Status fields, so for each row with same UserId i need to auto-increment its Status, not global.
There is three thing that come to mind when I read your question. One was an auto incrementing field which acts as your ID number. Updating a table with data that has no unique ID number. Searching for fields with the same Userid to Status
Mt First example is of a creating a table and your AUTO_INCREMENTing number ID:
CREATE TABLE tableNameHere
(
UniqueID int NOT NULL AUTO_INCREMENT,
FirstName varchar(255) NOT NULL,
StatusOrYourColumn int(100) NOT NULL,
PRIMARY KEY (UniqueUD)
)
More on auto incrementation.
You may have already built your table and now want to 'add' additional and or modify your fields using ALTER:
ALTER TABLE tableNameHere StatusOrYourColumn INT AUTO_INCREMENT PRIMARY KEY
But be careful, you don't want to overwrite your settings that you have already set.
Another Thing that came to my mind when reading was where you said Status and Userid where the same. You can find these using the WHERE clause like so:
SELECT * FROM tableName WHERE tableName.Userid = anotherTableOrTableName.Status
Using these queries you can update, remake, alter and query your database table.
I would like to know how to create view which also works even if the foreign key is NULL. For example we have table Person which has a primary key and two foreign keys:
IdPerson
FkName
FkSurname
Both foreign keys can be NULL. Now we also have two tables, table Name:
IdName
Name
And table Surname:
IdSurname
Surname
Now we create view to display name and surname for each Person:
CREATE VIEW `Database`.`ViewPerson` AS
SELECT `N`.`Name`, `S`.`Surname`
FROM `Person` `P`, `Name` `N`, `Surname` `S`
WHERE (`P`.`FkName` = `N`.`IdName`) AND (`P`.`FkSurname` = `S`.`IdSurname`)
The problem is, if the foreign key FkSurname is NULL, than that row will not be displayed even though FkName is defined. I want that even if both foreign keys are NULL it still returns row where both columns are NULL. Now I know that I could solve it by adding in table Name and in table Surname row, that has NULL under Name/Surname and then in the FkName and FkSurname reference a row that has NULL values under those two columns. But I would still like to find out if there is a solution where foreign key is NULL and the row is returned.
If I understand your question correctly, you want to get the corresponding values (even if null) for the Name and Surname fields in the Name and Surname table for each record in the Person table.
This seems like a straightforward case where LEFT JOIN would work correctly. So, based on your query above, the SQL would be:
CREATE VIEW Database.ViewPerson AS
SELECT
N.Name, S.Surname
FROM Person P
LEFT JOIN Name N ON N.IdName = P.FkName
LEFT JOIN Surname S ON N.IdSurname = S.FkSurname;
(sorry of the syntax isn't 100% correct, I didn't go through and create a test table to confirm it)
Suppose I have a blog post entity.
It has many attributes
It has comments attached to it.
It has many states (deleted/locked/invisible, etc).
It has many "tags". (keywords, school_id, user_id)
Obviously, comments should be its own table, with a many-to-one relationship to Blog table.
But what about "states" or "tags"? Would you put that in another table? Or would you stick that in many columns?
What about attributes...if they get too big? Because as my website grows, the blog post will have more and more attributes attached (title, author, blah, blah....). What happens if the attribute list goes as high as 100?
Here's a sample:
Again.. It's just a sample.. There are other approaches that you can use.
Here we go:
-- basic-basic blog
CREATE TABLE blog_entry (
blog_entry_id INT NOT NULL AUTO_INCREMENT,
blog_entry_title VARCHAR(255) NOT NULL,
blog_entry_text VARCHAR(4000) NOT NULL,
create_date DATETIME,
state_id INT
);
-- create a look-up table for your blog entry's state
CREATE TABLE be_state (
state_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (state_id)
);
-- create a look-up table for your blog entry's tag/s
CREATE TABLE be_tag (
tag_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (tag_id)
);
-- a table to store multiple tags to one entry
CREATE TABLE blog_entry_tags (
blog_entry_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, tag_id)
);
-- a table to store definitions of attributes
CREATE TABLE be_attribute (
attribute_id INT NOT NULL AUTO_INCREMENT,
name CHAR(30)
);
-- now have a table to which you can assign multiple attributes to one blog
-- of course, this is if I understand you correctly
-- where you want to have additional attributes
-- aside from the basic properties of a blog entry
-- and will allow you, if you choose to do it
-- to not necessarily have all attributes for each entry
CREATE TABLE blog_entry_attributes (
blog_entry_id INT NOT NULL,
attribute_id INT NOT NULL,
PRIMARY KEY (blog_entry_id, attribute_id)
-- PK enforces one blog entry may have only one attribute of its type
-- meaning, no multiple attributes of 'location' attribute,
-- for example, for one blog. Unless of course you wrote half the entry
-- in one location and finished it in the next.. then you should
-- NOT enforce this primary key
);
blog_entry - your main table, where the goods go
be_state - define them here, and insert their state_id values in blog_entry.state_id
be_tag - have multiple tags like we do here
blog_entry_tags - since you can possibly have many tags for one blog entry, store them here and insert blog_entry.blog_entry_id and the corresponding be_tag.tag_id together. one tag of its type per blog entry. meaning you can't tag entry#1 (for example) the tag php twice or more.
be_attribute - store attribute definitions here like location, author, etc
blog_entry_attributes - similar to blog_entry_tags where you can assign one or more than one be_attribute to a blog entry.
Again, this is just one approach.
first of all, states should be a tightly structured thing, so you should create separate columns for them. Think about what you need at the beginning, but you can easily add one or two more columns later.
Tags like keywords shouldn't be stored in columns, because the amount is growing rapidly over time. That wouldn't make any sense. So for that, build a table with id and keyword in it and a link table with post_id and keyword_id. You could also omit the keyword_id and directly link post_id and keyword.
Make sure that both columns combined define the primary key, so you can not end up with a keyword stored several time to one particular post.
For attributes it can be the same. It is not a bad practice to create an attribute table with attribute_id, attribute_name and maybe more information and a link table attribute_id and post_id and content.
You can also easily enhance it to be multilingual by using attribute_ids.
Comments are the same, stored in a separate table with a link to a user and a post: comment_id, user_id, post_id, content and maybe parent_id, which can be a comment_id if you want comments to be commentable again.
That's it for a brief overview.