Query data values where keys are different - php

I am having a little bit logic issue with querying data.
I have table with key and value columns
key has different values and that values stores data in valuecolumn
Example:
**key** **value**
car_name Honda
car_color black
car_name Audi
car_color white
.... .....
.... .....
I am able to select all car names or car colors
SELECT DISTINCT(value) as name FROM `cars` WHERE key = 'car_name';
SELECT DISTINCT(value) as color FROM `cars` WHERE key = 'car_color';
BUT, how can I combine these two values?
E.g
if car_name = Honda show only colors that Honda has in DB stored as car_color (in example case it would be black)
Current output
showing of course all the values under car_color (in example case it would be black, white)
Is it possible to combine these two keys/values?

At least you must have another column to cater your requirement. So i added a column and created table for a simple explanation. But your system need a good structure to archive your target.
We can add the object names into the new column we introduced. honda1 and Audi1 mean your object names. (Example )
If your unable to add a column, definitely this is not the answer for you and your requirement also impossible.
Then you can use the query like below
SELECT * FROM key_values WHERE cat IN (
SELECT cat FROM `key_values` WHERE `value` = 'honda')
AND `key` = 'car_color'
Note: here i added a 'key' and 'value' as column names, but not recommend to do with your live system.

Related

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

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).

Order a SQL Query by number of results

I want to do the following:
$searchParams is an array, which contains some strings (dynamicly generated).
Now the Statement would be something like this:
SELECT manufacturer FROM shop_articles WHERE manufacturer LIKE '".$searchParams."%'
But what I want is the result with the most matches. Can I code that in one statement?
So it would be something like
ORDER BY MATCHES DESC
How do I do that?
SELECT COUNT(*) AS matches, manufacturer FROM shop_articles WHERE manufacturer LIKE '".$searchParams."%' GROUP BY(manufaturer) ORDER BY matches ASC
For each param in your searchParam array you have to make a like clause
SELECT Manufacturer, COUNT(*) AS Matches FROM
FROM shop_articles WHERE (
manufacturer LIKE '".$searchParams[0]."%' OR
manufacturer LIKE '".$searchParams[1]."%' OR
...
manufacturer LIKE '".$searchParams[n]."%' OR )
GROUP BY Manufacturer
ORDER BY Matches
Actually you have to measure matching (likeness) between manufacturer and $searchParam. Unfortunatelly LIKE does not provide such functionality.
You may use Lavenshtein distances. See this post - Implementation of Levenshtein distance for mysql/fuzzy search?
SELECT manufacturer, COUNT(manufacturer) FROM shop_articles WHERE manufacturer LIKE '".$searchParams."' GROUP BY manufacturer ORDER BY COUNT(manufacturer) DESC
No, you cannot submit an array to the LIKE operator. It is more tedious than that. :-)
When your data are not yet properly regularized, so that you have variants of the manufacturer name in the PRODUCTS table (e.g. "HP", "Hewlett Packard") rather than an integer ManufacturerID, you have to go through the grunt work of reducing those variants to a single entity.
A typical approach for doing that (quite unavoidable) work is to create a Manufacturers table like this:
Table: MANUFACTURER
manufacturerid INTEGER primary key
manufacturername varchar
primarymanufacturerid INTEGER FOREIGN KEY REFERENCES MANUFACTURER(manufacturerid)
The last column allows you to associate a variant name (e.g. "HP") with the row where the main manufacturer record is stored (e.g. "Hewlett Packard").
124, Hewlett Packard, 124
367, HP, 124
The row where primarymanufacturerid = manufacturerid is the the main entity.
Then you could do this during an interim cleanup phase when you have not yet added a manufacturerid to the PRODUCTS table but it still has the name:
select * from products
where manufacturer in
(
select manufacturername from manufacturer
where primarymanufacturerid =
(
select primarymanufacturerid from manufacturer
where manufacturername = 'Hewlett Packard'
)
)
P.S. With a database engine that had support for functions and stored procedures, you could write your own function that accepted a delimited string of name variations, built a dynamic SQL statement, possibly using a temporary table to store the variant names one name per row, and returned a count of the matches. This would be a resource-intensive approach recommended only to assist in the clean-up phase -- not something I'd put into production for end-users to consume as their daily bread.
P.P.S. And, of course, once you have your MANUFACTURER table properly created, with the primarymanufacturerid references completed, you could add a [manufacturerid] column to your PRODUCTS table and update it accordingly, and then dispense with all of this roundabout stuff.
$sql = 'SELECT manufacturer FROM shop_articles WHERE 1=1';
for($i=0;$i
by this you can run query for $searchParams array dynamically

MySQL - Searching in a multiple value field

In my database table I have the following fields:
Table Supplier:
id
name
vehicles
A supplier can have multiple vehicles. The field 'vehicles' will store multiple values. At the moment I am delimiting the values on a 'pipe' symbol, although this can be changed to a comma if need be.
On my front-end form I have a checkbox list - a user can select multiple vehicles. The back end script needs to do a search and bring back all suppliers that contain any of the specified vehicle id's.
So in other words we are searching with multiple values in a multiple value field.
The checkbox list name is vehicle_type[] and will end up in the $_POST array as (for example):
Array
(
[0] => 1
[1] => 4
[2] => 6
)
Is this possible to do? I could obviously do this using a join table but ideally I would like to do it this way. I am using PHP as my scripting language if that helps.
The field 'vehicles' will store multiple values. At the moment I am delimiting the values on a 'pipe' symbol, although this can be changed to a comma if need be.
Please don't do that. Storing delimited data in a text field is no better than storing it in a flat file. The data becomes unqueryable.
You want a nice, happy, normalized database.
CREATE TABLE Suppliers (
supplier_id INTEGER PRIMARY KEY,
...
);
CREATE TABLE Vehicles (
vehicle_id INTEGER PRIMARY KEY,
...
);
CREATE TABLE Supplier_Vehicles (
supplier_id INTEGER NOT NULL REFERENCES Suppliers(supplier_id),
vehicle_id INTEGER NOT NULL REFERENCES Vehicles(vehicle_id),
UNIQUE KEY(supplier_id, vehicle_id)
);
-- Grab all the Vehicles for Supplier 39
SELECT Vehicles.*
FROM Vehicles, Supplier_Vehicles
WHERE Supplier_Vehicles.supplier_id = 39
AND Supplier_Vehicles.vehicle_id = Vehicles.vehicle_id
The checkbox list name is vehicle_type[] and will end up in the $_POST array as (for example) [...] Is this possible to do?
It's very possible, and is a good idea. Try it and find out how well it works.

Categories