Order a SQL Query by number of results - php

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

Related

Unique Columns in SQL Views

In my database I have one table that contains a complete list of products, and another table that contains the same list of products on the x-axis, with a list of customers on the y-axis, where the value for each product can be 1 or 0 depending on whether that customer can view that product. My SQL looks like this:
SELECT products.product_code, products.product_type, products.product_category, products.product_title, products.product_description
FROM product_lists
INNER JOIN products
ON product_lists.product_code=products.product_code
WHERE product_lists.customer="1"
ORDER BY products.product_code
My problem is that I would like to create a view of this result for each customer to use as that customers product table, however when I create it I get the message "This table does not contain a unique column. Grid edit, checkbox, Edit, Copy and Delete features are not available." even though the product_code field is set as a primary key in both the products table and the product_lists table.
How can I create a join/view that uses the primary key from the table(s) it was created from? In short I would like the product_code field to become the primary key of my view.
Thanks!
I think the problem is the join. You can fix this by moving the condition to the where clause. MySQL doesn't allow subqueries in the from, but it does in the where:
SELECT p.product_code, p.product_type, p.product_category, p.product_title, p.product_description
FROM products p
WHERE EXISTS (SELECT 1
FROM product_lists pl
WHERE pl.product_code = p.product_code AND
pl.customer = 1
)
ORDER BY p.product_code;

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.

Get an array of all columns starting with the same characters.

This is quite difficult to explain in the title, so I'll do my best here. Basically I have a column in a MySQL products table that contains rows like:
FEL10
FEL20
FEL30
PRO05
PRO07
PRO08
VAI12
VAI13
VAI14
These are the categories ("FEL","PRO","VAI") and a identification number of my products ("10", "20" and so on). I need an SQL select query that creates me a textual array like:
FEL*
PRO*
VAI*
With this array I need to create a listbox, that allows me to choose a category (regardless of the identification number). Once I choose a category, let's say PRO*, I will need to do the reverse action: print all the products info related to PRO05, PRO07 and PRO08.
How do you think you can achieve this? I have been trying using the DISTINCT statement but I need to filter only the first characters, otherwise it will be useless. I also tried the SUBSTRING() and LEFT() functions, but they seem not to be working (I get an SQL Syntax error).
--
Thanks for your help as always
What is wrong with?
SELECT distinct left(col, 3) as category FROM `table1`
MySQL LIKE to the resque:
SELECT col1 FROM table1 WHERE col1 LIKE 'FEL%';
This way you have to add all cases using OR.
Alternative - REGEXP:
SELECT col1 FROM table1 WHERE col1 REGEXP '(FEL|PRO|VAI).*'
Then it's just a matter of writing proper regex.
I would use extra col to group your items - to avoid such selecting altogether (which should be quite expensive on bigger dataset).
https://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
To get the list of the 3-letter codes use:
select distinct left(combicode, 3)
from mytable;
When a user selects one of the values use this to get all matching entries:
select *
from mytable
where combicode like concat(#category, '%');
(Aside from that: It's a bad idea to have concatenated values in one column. Why not have one column for the category and another for the product code? Then there would be no problem at all.)

Search by serialized value

This is the query i use for getting the data out of my database
SELECT
product_description.name as name,
product.image as iurl
FROM
product_description, product
WHERE
product_description.product_id = product.product_id
AND product.product_id
AND product.product_id = '33';
Why is this query producing double results?
I want to automaticly search by multiple values (id's) stored in database instead of manually adding the AND product.product_id='?' part. Values are stored in serialized form.
something like
... AND product.product_id in (setting.value WHERE key='featured');
I know that query is not correct, just trying to show what i want.
table 'setting':
value | key
-------------------
23,43,28 | featured
Solution
To get the details of all products which are stored in your settings table (comma separated) you can use FIND_IN_SET()
SELECT
product_description.description,
product.name,
product.id
FROM
product_description, product
WHERE
product_description.id = product.id
AND FIND_IN_SET(product.id, ( SELECT value FROM setting where `key` = 'featured' ) );
SQLFiddle
Note: The reason why you see duplicated entries could be because there are multiple descrioptions for a particular product, you can handle this using GROUP_CONCAT
The following should work
Epilogue
Your database design is not good, It should be something like
product -- All my products go here
product_details -- Details of all the products ( A product could have multiple details)
categories -- eg: Featured, Seasonal
product_categories -- association of product to categories
This is somehow breaking the relational paradigm, you should have three entries with values 23, 43 and 28.
Then again I'm guessing field value is a varchar (do you know "value" and "key" are reserved words by mysql ?) so you might want to look inside the string to find pattern ",23," inside the field. Something like : WHERE CONCAT(',', field_value, ',') LIKE "%,23,%"

Items sql table

I am building a textbased game, and I have problem of how to build/structur my SQL table for items.
Item can be anything from weapon, a fruit, armor, etc. But I'm not sure how to properly design this.
For example
Iron Sword Str +4 Health +3
(Or something like that)
But if its a fruit item
Fruit of Health (lol)
+5 health when eated
Any tips or ideas? The question is How do I structure this SQL table?
Store different types of object in different tables.
Give each table the proper columns for the respective kind of object it stores.
CREATE TABLE Weapons (WeaponId INT PRIMARY KEY, Name VARCHAR(20), Strength INT);
CREATE TABLE Foods (FoodId INT PRIMARY KEY, Name VARCHAR(20), HealthBonus INT);
If you want all types of objects to have some common attributes, like weight or purchase price, then you could create a general Items table that has those common attributes.
CREATE TABLE Items (ItemId INT AUTO_INCREMENT PRIMARY KEY,
Weight NUMERIC(9,2), Cost NUMERIC(9,2));
You'd make the WeaponId and FoodId primary keys from the other tables would each match one of the ItemId values in Items. When you want to create a new weapon, you'd first add a row to Items which would generate a new ItemId value, then use that value explicitly as you insert into Weapons.
See the Class Table Inheritance pattern.
Re your question below.
If you are querying for a specific weapon, you can join:
SELECT * FROM Items i JOIN Weapons w ON w.WeaponId = i.ItemId
WHERE w.Name = 'Iron Sword';
If you are query for all items in the character's backpack, you'd have to do multiple joins:
SELECT i.*, COALESCE(w.Name, f.Name, t.Name) AS Name,
CONCAT_WS('/',
IF (w.WeaponId, 'Weapon', NULL),
IF(f.FoodId, 'Food', NULL),
IF(t.TreasureId, 'Treasure', NULL)
) AS ItemType
FROM Items i
LEFT OUTER JOIN Weapons w ON w.WeaponId = i.ItemId
LEFT OUTER JOIN Foods f ON f.FoodId = i.ItemId
LEFT OUTER JOIN Treasure t ON t.TreasureId = i.ItemId
etc.;
If a given Item matches a Weapon but not a Food, then the columns in f.* will be null. Hopefully a given ItemId matches an Id used in only one of the specific subtype tables. On the other hand, it allows a given item to be both a weapon and a food (for instance, vegan cupcakes, which can be effective projectiles ;-).
Sounds like you need a table of attributes (strength, health, etc.). Then a table of the items (name, description, etc) and an association linking the two together (obviously linking by related id's rather than text for normalization, but this is just to demonstrate).
Item Attr Value
Iron Sword Str +4
Iron Sword Hlth +3
Fruit Hlth +5
Right answears given above.. They are different approaches... The second one requires good knwledge of OOP.
I want to mention an other thing, I suggest you read some tutorial on Entity Relational diagram-design. I gues for a game you will probably need to study a few basic things only so it will take you only some hours I guess.
There are many things to consier while designing... for example:
Entity = A thing that can logically stand on its own with its own attributes: Customer, Supplier, Student, Departement are some strong entities etc. Works for, belongs to etc are not entities but relations that associatin entities together.
An entity becomes a table. Strong entities (that have no dependencies) become tables with a simple primary key and usually without accepting any foreign keys. Phone number is not a strong-indepndent entity every time a customer is deleted the phone has no menaing, every time a phone is deleted hte customer has still meaning. Phone is an attribute but because of multiple values it becomes finally a table.
All these are not to tutor er design just to mention that db design in not something to take lightly, it can save you or give you big pain... depends on you.

Categories