Store data as varchar, or as tinyint and use switch - php

Probably a very simple question, but I'm not sure how to test it myself..
Imagine I have a mysql table with let's say, 30000 rows.
Each row has a column car_brand.
In my phpform I have a select with by example, the following car brands: Mercedes, Audi, Chevrolet, Volkswagen, Opel.
What is the fastest (less memory using) way to show the car brand to the user?
Use tinyint and say 0 = Mercedes, 1 = Audi, 2 = Chevrolet... And use a CASE in the SELECT statement or use a php switch() before showing it in a HTML table OR is it better to save the data as a varchar?
Hope someone have a clear answer ;)

The correct way is to use a separate reference table for the brands:
create table CarBrands (
CarBrandId int not null primary key auto_increment,
BrandName varchar(255) not null
);
Then refer to the car brand in other tables using CarBrandId and use a join to get the brand name. This is the right way to handle a reference table.
If you are really opposed to a reference table, then you can use enum.

Related

How to Use Auto Increment in Varchar data Type in PHP an MYSQL?

can anyone tell us how to use auto increment in varchar data type?
i have look for other question and people always ask to use interger or use trigger. but however this is my college's project that has a rule for us to use varchar.
Automatically generated based on last Product ID existing in the database
Ex. If the latest Product ID is ‘PR004’, then the new id will be ‘PR005’
so, we must set auto increment in php right?can someone tell me how to use this?
thank you
MYSQL 5.7.5:
You can accomplish the goal using Generated Columns and this.
Not tested
CREATE TABLE TEST (
ProdID VARCHAR(20) AS CONCAT('PR','',PID) STORED,
PID INT auto_increment)
For your convenience,
MSSQL:
The easiest method is to simply make a calculated column. It uses what is known as a "calculated" column in conjunction with an IDENTITY column.
CREATE TABLE Test
(
ProdID AS CAST('PR'+RIGHT('000'+CAST(RowNum AS VARCHAR(3)),3) AS VARCHAR(30)) PERSISTED
,ProdName VARCHAR(30)
,RowNum INT IDENTITY(1,1)
);
INSERT INTO Test (ProdName)
SELECT 'Thread' UNION ALL
SELECT 'Button Thread' UNION ALL
SELECT 'Coat Thread';
SELECT ProdID, ProdName FROM Test;
That returns the following (notice that the auto-increment worked):
ProdID ProdName
------------------------------ ------------------------------
PR001 Thread
PR002 Button Thread
PR003 Coat Thread

mySQL query to get only display

I wanted to ask one question as my query skills are not that great and I have been learning mySQL for the last week. This attachment I have shows what happens when I run the following query:
SELECT * FROM clothing, sizing WHERE id = "101";
You might notice that it produces the same id number, same name, same type, same brand_id,same price, and a lot of null values. Is there a query which I can run which only displays columns which do not have null values?
You can select the rows that dont have null values in given columns, or you can use IFNULL.
IFNULL(yourColumn,0)
This will display 0 instead of Null, but beware that NULL and 0 is not the same thing.
Null is "nothing" / undefined, 0 is a numerical value.
You can have issues multiplying with NULL, so you can do for instance:
SELECT (numProducts * IFNULL(productPrice,0))
FROM ...
You can also use CASE or IF to select differenct colums and alias them :-)
External link to docs: https://dev.mysql.com/doc/refman/4.1/en/control-flow-functions.html
Yes above solutions will work only if that column has default value set to null,if its not set then you need to check blank ,i mean to say IFNULL(productPrice,0) will not work you need to do as below,
SELECT (numProducts * IF(productPrice='',0,productPrice))
FROM ...
You are basically asking about two problems that I will address separately in this answer.
1 - More than one record is returned
You should follow mathielo and Olavxxx's comments regarding the use of JOIN.
The query as shown in your question is a cartesian product between your tables clothing and sizing. What the query is basically asking is "I want only the record with id 101 in one of the table, as well as all the records in the other table".
Judging by the rest of your question, this is not what you want. So I take it there is a relationship between rows in clothing and sizing. I will assume that a clothing can only have one size, and that this relationship is represented by a foreign key to sizing. Here the minimum the tables should contain for that to work (I do not reuse your model because from the details in the question I can only guess, not know, what your exact table model is):
clothing:
id: primary key
size_id: foreign key to sizing
sizing:
size_id: primary key
As a consequence, the following query should return all records corresponding to the selected clothing and associated size:
SELECT *
FROM clothing AS c
JOIN sizing AS s ON c.size_id = s.size_id
WHERE c.id = 101
Your relationship between your two tables may actually be different from what I have just modeled. If that is the case, I still hope the above example is enough to get you started in the right direction.
2 - Lots of NULL values
This part of the question needs to be precised. Is it that you do not want the records with NULL values for some columns to be returned, or is it that you just do not want to get the content of these columns? Or maybe you want to use a default value?
If it is the records you want to filter out, you should add <column> IS NOT NULL conditions in your WHERE clause. One for each of the columns you are interested in.
If it is the columns you do not want to get, do not use SELECT * but instead explicitely list the columns you want, for example:
SELECT id, name, price FROM clothing
If it is about using a default value instead, you need to use IF in the SELECT clause as in Supriya's answer. Another example:
SELECT name, size, IF(shoulder IS NULL, 'Default', shoulder)
FROM clothing

How to hash auto increments in mysql

Is there a way to make mysql hash the auto increment values for its tables?
For example with md5?
id - name
1 - New York
2 - Chicago
3 - Sydney
4 - Berlin
what I'm trying to get
id - name
c4ca4238a0b923820dcc509a6f75849b - New York
c81e728d9d4c2f636f067f89cc14862c - Chicago
eccbc87e4b5ce2fe28308fd9f2a7baf3 - Sydney
a87ff679a2f3e71d9181a67b7542122c - Berlin
Thanks in advance
EDIT:
I think I need to clarify the question a little more, what im trying to do is not Call the ID's but Insert them. In the moment the ID column is an int field which I will change to varchar.
I want to save the identifiers as Hashed in the DB not call them with mysql SELECT. Thanks
If you really need this, for some reason, you can achieve it with a help of a separate table for sequencing and a BEFORE trigger
Table schemas:
CREATE TABLE table1_seq
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE table1
(id VARCHAR(32) NOT NULL DEFAULT 0, name VARCHAR(32));
The trigger
DELIMITER $$
CREATE TRIGGER tg_bi_table1
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq () VALUES ();
SET NEW.id = MD5(LAST_INSERT_ID());
END$$
DELIMITER ;
Now you can insert rows into your table1 table
INSERT INTO table1 (`name`) VALUES ('New York'),('Chicago'),('Sydney'),('Berlin');
or select
SELECT * FROM table1 WHERE id = MD5(2);
Here is SQLFiddle demo
All the answers above lack a good understanding of the need to use hashed id's.
Hashing the auto increment id violates the whole concept.
The concept you want to reach is that the next id will be unpredictable from the previous.
In the idea of hashing the id the next id of the md5( 1 ) is the md5( 2 ).
If you use the names that helps.
It would be best to create the hash from several fields.
The fields together should be unique to create a unique hash.
Maybe i did not understand the question, but this is my opinion:
I think you try to create a hash table. So insert id field as hash of your data (md5(name)).
But if not, use a table trigger to generate field hash after insert.
MySQL Docs say..
Functions cannot be added as COLUMN DEFAULTS - except for now() that
is internally represented as a synonym of CURRENT_TIMESTAMP.
A best bet would be to do this...
UPDATE yourtablename SET id=MD5(id) WHERE 1=1;
or to run a TRIGGER
Something like ... (Not 100% correct... just giving you an idea)
CREATE TRIGGER generateMD5forID BEFORE INSERT ON `yourtablename` FOR EACH ROW SET id = MD5(id);
The Answers here brought up an Idea in me.. I think that will work as the best solution for now.. but if there is someone who knows an easier way I'm glad to hear it.
Solution:
Create a new table with an auto increment field like id or count, which you will always increment first and use the last ID out of that table to hash it for the primary field of your other table.

Whats wrong with these SQL statements?

Problem 1: Using the SQL CREATE TABLE statement, create a table, MOVSTARDIR, with attributes for the movie number, star number, and director number and the 4 acting awards. The primary key is the movie number, star number and director number (all 3), with referential integrity enforced. The director number is the director for that movie, and the star must have appeared in that movie.
Load MOVSTARDIR (from existing tables) using INSERt INTO.
My answer:
CREATE TABLE MOVSTARDIR
(MVNUM SHORT NOT NULL, STARNUM SHORT NOT NULL, DIRNUM SHORT NOT NULL, BESTF TEXT, BESTM TEXT, SUPM TEXT, SUPF TEXT)
ALTER TABLE MOVSTARDIR
ADD PRIMARY KEY (MVNUM,STARNUM,DIRNUM)
INSERT INTO MOVSTARDIR
SELECT MOVIE.MVNUM,STAR.STARNUM,DIRECTOR.DIRNUM... BESTF,BESTM,SUPM,SUPF
FROM MOVSTAR, DIRECTOR, MOVIE
WHERE MOVSTAR.MVNUM=MOVIE.MVNUM
AND MOVIE.DIRNUM=DIRECTOR.DIRNUM`
*Its giving me an error saying something is wrong with "create table" statement and it highlights the word "alter" in the SQL statement. Also how do i add referential integrity?*
Problem 2:List the directors in MOVSTARDIR with the total awards won from the 4 award categories included in the table. List the director name (not number), and the count in each of the 4 categories and the sum for all 4 categories. Group the report by the director name (i.e. one line per director, each director appears once), and order it by the sum (descending). Only show lines where the sum is more than 3.
SELECT DISTINCT DIRNAME, COUNT(BESTF) AS BESTFE, COUNT(BESTM) AS BESTML,
COUNT(SUPM) AS SUPML, COUNT(SUPF) AS SUPFE,
(COUNT(BESTM) COUNT(BESTF) COUNT(SUPM) COUNT(SUPF)) AS TOTAL
FROM MOVSTARDIR, DIRECTOR
WHERE MOVSTARDIR.DIRNUM=DIRECTOR.DIRNUM
AND ((BESTM IS NOT NULL) OR (BESTF IS NOT NULL) OR (SUPM IS NOT NULL)
OR (SUPF IS NOT NULL))
GROUP BY DIRNAME
HAVING (COUNT(BESTM) COUNT(BESTF) COUNT(SUPM) COUNT(SUPF)) 3
ORDER BY (COUNT(BESTM) COUNT(BESTF) COUNT(SUPM) COUNT(SUPF))DESC`
*Problem with this is it list all records not just wins*
if the database is needed i can send the data base through email.
For Problem 1:
If you are using mysql, the query for create should be as follows
CREATE TABLE `MOVSTARDIR` (
`MVNUM` SMALLINT NOT NULL ,
`STARNUM` SMALLINT NOT NULL ,
`DIRNUM` SMALLINT NOT NULL ,
`BESTF` TEXT NOT NULL ,
`BESTM` TEXT NOT NULL ,
`SUPM` TEXT NOT NULL ,
`SUPF` TEXT NOT NULL
);
You're missing the semicolon after each of the statements, causing Access to treat the entire text as one statement.
Your tags show MySQL, SQL Server and SQL. The syntax of the SQL can vary according to the RDBMS.
Assuming you are using MySQL, these are the issues with your query.
a. Data type - There is no SHORT in MySQL. You can use SMALLINT
b. You need to add semi colons after each sql statement
Even if you are using any other RDBMS, you need to refer the corresponding SQL manual and verify that you specify the exact data types.
Access doesn't allow to run a batch of queries, only one by one.
So, run first CREATE TABLE, then ALTER and so on.

DB Design; or Conditional Selects with json data

I have a DB with several tables that contain basic, static ID-to-name data. 2 Columns only in each of these reference tables.
I then have another table that will be receiving data input by users. Each instance of user input will have it's own row with a timestamp, but the important columns here will contain either one, or several of the ID's related to names in one of the other tables. For the ease of submitting and retrieving this information I opted to input it as text, in json format.
Everything was going great until I realized I'm going to need to Join the big table with the little tables to reference the names to the ID's. I need to return the IDs in the results as well.
An example of what a few rows in this table might look like:
Column 1 | Column 2 | Timestamp
["715835199","91158582","90516801"] | ["11987","11987","22474"] | 2012-08-28 21:18:48
["715835199"] | ["0"] | 2012-08-28 21:22:48
["91158582","90516801"] | ["11987"] | 2012-08-28 21:25:48
There WILL be repeats of the ID#'s input in this table, but not necessarily in the same groupings, hence why I put the ID to name pairings in a separate table.
Is it possible to do a WHERE name='any-of-these-json-values'? Am I best off doing a ghetto join in php after I query the main table to pull the IDs for the names I need to include? Or do I just need to redo the design of the data input table entirely?
First of all:
Never, ever put more than one information into one field, if you want to access them seperately. Never.
That said, I think you will need to create a full N:M relation, which includes a join table: One row in your example table will need to be replaced by 1-N rows in the join table.
A tricky join with string matching will perform acceptably only for a very small number of rows, and the WHERE name='any-of-these-json-values' is impossible in your construct: MySQL doesn't "understand", that this is a JSON array - it sees it as unstructured text. On a join table, this clause comes quite naturally as WHERE somecolumn IN (1234,5678,8012)
Edit
Assuming your Column 1 contains arrays of IDs in table1 and Column 2 carries arrays of IDs in table2 you would have to do something like
CREATE TABLE t1t2join (
t1id INT NOT NULL ,
t2id INT NOT NULL ,
`Timestamp` DATETIME NOT NULL ,
PRIMARY KEY (t1id,t2id,`Timestamp`) ,
KEY (t2id)
)
(you might want to sanity-check the keys)
And on an insert do the following (in pseudo-code)
Remember timestamp
Cycle all permutations of (Column1,Column2) given by user
Create row
So for your third example row, the SQL would be:
SELECT #now:=NOW();
INSERT INTO t1t2join VALUES
(91158582,11987,#now),
(90516801,11987,#now);

Categories