mySQL query to get only display - php

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

Related

How to retrieve count values as multiple columns using group by in single query in MySQL?

I am writing a complex MySQL query. My actual query is more complex than I mentioned below.
I have a table named example and columns are id, name, option_1, option_2 . Of course id column is PK . I want to retrieve like this:
SELECT `id`,`name`,count(`option_1`),count(`option_2`)
My problem is I want to use "GROUP BY `id`" for count(`option_1`) and "GROUP BY `name`" for count(`option_2`) respectively. Now I have to break down it into multiple code in my php code.
How can I achieve what I want in a single query?
What you're asking for doesn't make a ton of sense. You want option 1 grouped by id and option 2 grouped by name, and you want to show all four columns in one result set.
First of all, if id is a primary key, then the count will just be the number of rows in the table since there will be no duplicate ids.
Second, even if id wasn't a primary key, and there were duplicate values, the grouping is different, so the counts represented in your result set would be grouped incorrectly.
Given that id is a primary key, perhaps your intention is actually to get a total count of the rows in the table. Perhaps this query would suit your needs?
SELECT
name,
COUNT(option_2) AS options
FROM
example
GROUP BY
name
UNION ALL
SELECT
'Total' AS name,
COUNT(*) AS options
FROM
example
This should get you a count of all the option_2 values, grouped by name, with the final row having a name of 'Total' and the count being the total number of rows in the table.
Aside from that, I'm not sure you're going to find the answer you're looking for due to the problems you would encounter matching up groupings.

Adding a Row into an alphabetically ordered SQL table

I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.

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.

Using PHP to merge duplicate records from MySQL database in CakePHP

I have a table that stores data that has been entered regarding the amount of waste put in a bin. So my table looks like this:
Material | Weight
===================
Paper | 10
Plastic | 5
Paper | 7
As you can see, I'm going to have duplicate data in the table. At the moment I have multiple instances of different materials, and they all have different weight values attached to them.
Is it possible in PHP to get these duplicate entries, combine them in to one entry, and then display them? So the code would take the 10Kg of Paper and add it to the other instance of paper in the table (7Kg) and then output the value?
I have tried the GROUP BY in MySQL, but all that will do is combine all of the entries and give me the value of the top record, which isn't right.
Thanks!
Use MySql, with a SUM column. This will sum up all values for that column, for each grouping. This is assuming the weight column is just a number (10 instead of 10kg).
SELECT
`material`,
SUM(`weight`) AS `weight`
FROM `material_weights`
GROUP BY `material`
If the weight column isn't just a number (10kg instead of 10), then there will be issues.
If all weights are in KG, then you should just remove the 'kg' value from each weight, and convert the weight column from text into a numeric column.
If there are different kinds of weights (KG, LB, G, etc), then the best way would be to have an extra field in the table, with the weight converted into KG.
Since all your data seems to be in strings, it seems like you would be best served by using a php migration script to examine your data and then combine duplicates. First thing you want to do is determine which Materials have duplicates.
SELECT Material FROM {TABLE} GROUP BY Material HAVING COUNT(*) > 1;
From there you should loop through the materials that come back, and grab all rows with the Material value.
SELECT * FROM {TABLE} WHERE Material = '{$material}';
This will give you all the rows labeled that Material. From there, apply any transformations (just in case there are values labeled g, for example) to the numeric value to ensure you're operating on the same type of value. Then you'd delete all the rows with that type of material. (You have a backup, right?)
DELETE FROM {TABLE} WHERE Material = '{$material}';
Lastly, insert the value you just determined.
INSERT INTO {TABLE} (Material, Weight), ('$material', '$weight');
SELECT
material,
SUM(CAST(REPLACE(weight, 'kg', '') AS UNSIGNED)) AS weightsum
FROM
tbl
GROUP BY
material
You can use the SUM() function with GROUP BY to get the sum of the weight per unique material. In your case, your weight field appears to be a string. You can simply take out the 'kg' from each value using REPLACE, then convert it to an integer, which is then passed to SUM().

SQL return only not empty columns from row as new row

I'm in the situation where my client e-mails me an excel-file with 50 columns of data extremely un-normalized. I then export it to CSV and upload into MySQL -- single table. The columns are for different ingredients (10 columns of data for each ingredient -- title, category, etc) and then 40 different columns for characteristics on each ingredients. So each ingredient in the table has all of these 50 columns even though every column doesn't apply for that ingredient.
My question is if I can create a SQL that selects only filled in characteristics for one selected ingredient and leaves out all of the other columns?
(I know that another option is to build my own CSV-parser that created multiple tables and then write SQL for them instead, but I wanna investigate solving this as is first. If that's not possible then I just have to face that and build a parser ;P)
This is as far as I came but this doesn't completely exclude columns not filled in (or that contains "nei".
SELECT
IF(`Heving-vanlig-gjaerbakst` <> '' AND `Heving-vanlig-gjaerbakst` <> 'nei', `Heving-vanlig-gjaerbakst`, 'random') AS `test1`,
IF(`Frys-kort` <> '' AND `Frys-kort` <> 'nei', `Frys-kort`, 'random') AS `test2`
... and for the 38 other rows ...
FROM x
WHERE id = 123
And I'd rather not solve this in the PHP-code by skipping empty rows =P
Example row (column names first):
g1 gruppe ug1 undergruppe artnr artikkel beskrivelse status enhet ansvar prisliste Heving-vanlig-gjaerbakst Heving-soete-deiger Deig-stabilitet Smaksgiver Saftighet Krumme-poring Skorpe Volum Konservering Skjaerbarhet Frys-lang Frys-kort Kjoel Holdbarhet E-fri Azo-fri Mandler Aprikoskjerner Helmiks Halvmiks Base Konsentrat Utstrykning Bakefasthet Frukt-Baerinnhold Slippegenskaper Hindre-koksing Palmefri Fritering Smidighet Baking Kreming Roere Fylning Dekor Prefert Viskositet Cacaoinnhold Fet-innhold
100150 Bakehjelpemidler 100150200 Fiber/potetprodukter 10085 Potetflakes sekk 15 kg Egnet til lomper, lefser, brød og annet bakverk. B... Handel Sekk Trond Olsen JA xxx xxx xxx
As you can see most columns are empty here. X, XX and XXX is a form of grade-system, but for some columns the content is instead "yes" or "no".
And as I said, the first 10 columns are information about that product, the other 40 is different characteristics (and it's those I wanna work with for one given product).
It sounds a bit as if you'd like to convert the table you have into two tables:
CREATE TABLE Ingredients
(
g1 ...,
gruppe ...,
ug1 ...,
undergruppe ...,
artnr ... PRIMARY KEY,
artikkel ...,
beskrivelse ...,
status ...,
enhet ...,
ansvar ...,
prisliste ...
);
I've opted to guess that the artnr is the primary key, but adapt what follows to the actual primary key. This table contains the eleven (though your question said ten) columns that are common to all ingredients. You then have another table which contains:
CREATE TABLE IngredientProperties
(
artnr ... NOT NULL REFERENCES Ingredients,
property VARCHAR(32) NOT NULL,
value VARCHAR(3) NOT NULL,
PRIMARY KEY(artnr, property)
);
You can then load the populated columns from your original table into these two. At worst, there'd be 40 entries in IngredientProperties for one entry in Ingredient. You might make 'property' into a foreign key reference to a defining list of possible ingredient properties (a third table that defines the possible values for the properties - basically, a record of the column names from your original table). If you add the third table, it might logically be called IngredientProperties (too), in which case the table I called IngredientProperties needs to be renamed.
You can then join Ingredients and IngredientProperties to get the information you want.
I'm not sure that I recommend this solution; it is basically a use of the 'Entity Attribute Value' approach to database design. However, for extremely sparse information like you seem to have, and when used with the constraint of the third table.
What you can't sensibly do is handle all possible combinations of 40 columns as that number grows exponentially with the number of columns (and is pretty large with N = 40).

Categories