SQL - Writing an order by case or if statement - php

Some beforehand layout knowledge about the database
I have a database with my store items that has the following four fields
`c.postdate`, `c.regularprice`, `c.isonsale`, `c.saleprice`
The standard call to the database is something like the following:
query("SELECT * FROM items WHERE `s.cat` IN (idsarrayishere) AND `s.isactive` = '1' $sort")
This works to just pull everything from the database. The default value for $sort is just blank since I am not worried about that at this time as I will most likely just sort them by newest date using the c.postdate field listed above.
Sorting items by specific variables
I would love to be able to take advantage of the ORDER BY CASE that mysql has to be able to sort my items from price highest - lowest and vice versa. The issue I am running into is I don't know how to write the query so that if the c.isonsale = '1' then order by the the c.saleprice instead of the c.regularprice, and if it's not, order by the c.regularprice, so when they select lowest price first, it will show them the sale items in with the lower priced items. This is what I've found so far for ORDER BY with case
ORDER BY
CASE `type`
WHEN 'Member' THEN LNAME
WHEN 'Group' THEN GROUPNAME
ELSE 1 END
ASC
Not sure the correct way to adapt this to what I am trying to do though. Any help on this matter would be appreciated as the MySQL doc's are a little vague when learning this process.
Edit
In response to the reply about adding sample data and expected result since my post isn't clear about this apparently, say I have these three items
item => 1
c.regularprice => 9.99
c.isonsale => 0
c.saleprice => 0
item => 2
c.regularprice => 19.99
c.isonsale => 1
c.saleprice => 6.99
item => 3
c.regularprice => 10.99
c.isonsale => 0
c.saleprice => 0
I need to be able to sort by price lowest first, then go to highest. So with this example, I would expect item 2, item 1, item 3 in that order. Even though the regular price of item 2 is higher than the others, its on sale and cheaper so should show first.

Since you're only switching between two possible options, I think IF will be simpler than CASE.
ORDER BY IF(c.isonsale, c.saleprice, c.regularprice)
That IF expression will return the sale price if the item is on sale, and the regular price if it isn't.

Related

Storing order information (I have 2 options) like in a todo list

I have a list of items (like a todo list), that need to be presented in a certain order. This order may change, and new items may be added (at any position) and items deleted. I'm trying to decide what's a good way to store the order of these items, in a way that would make easy to update the list and display the data.
I could store the order information in a field for each item. This makes it easy to just sort the items by that field. But the problem is if I want to add a new item at the top of the list, I have to modify all other items in that list (if I have 50 todos, then I have to modify 50 records).
The other option is to store the order of the items in the todo list object itself. So I'd store the order as a string 23,45,34,100. If the order changes, I just change that 1 field in the todo list object. The problem is that to present the items, I can't simply get them ordered. I have to figure out a way to order the items based on that order string, after I retrieve the items from the database.
So any tips on a good way to store the order bit? I have these 2 options, but I'm open to other ways. I'm looking for something that makes it easy to present the data, but not be too difficult to update the order when it changes.
Sample data
id value order
----------------------
1 item 5 5
2 item 1 1
3 item 4 4
4 item 2 2
5 item 3 3
output
------
item 1 (id 2)
item 2 (id 4)
item 3 (id 5)
item 4 (id 3)
item 5 (id 1)
SELECT value
FROM Sampledata
ORDER BY
CASE WHEN id=2
THEN value END,
CASE WHEN id=4
THEN value END,
CASE WHEN id=5
THEN value END,
CASE WHEN id=3
THEN value END,
CASE WHEN id=1
THEN value END;
You could use an associative array, but the keys could be generated with uniquid().
You should store an ID as part of each item (perhaps generated with uniqid()), and keep an array of those IDs in the order in which they are sorted. Then you keep your order as an array of IDs.
Change the order of the sort array, and you change the order of your output. It is easy enough to output your values according to the sort array.
$values = array(
'4f7684747c784' => array( ... ),
'4f76846f0561c' => array( ... ),
'4f76847aa7759' => array( ... ),
);
$sort = array('4f76846f0561c', '4f7684747c784', '4f76847aa7759');
foreach($sort as $key) {
// do something with $values[$key]
}

Database design for price data

I have a database that stores components in a component table.
There is a second table for component prices. This table has a field that maps to a component id. My price table needs to store information for a bunch of different prices (10, 100, 1000, 10K, 100K, 1M). The thing is, there is a possibility in the future to store other price types such as 25K or 50K.
As of right now, my price table looks like this:
id component_id type price
where the type can take values from 1-6 currently. This is good because it will allow me to add new price types in the future very easily.
The other option is a price table that looks like this:
id component_id price_10 price_100 price_1000 price_10K price_100K price_1M
But in this case, I would need to add a new field every time a new price type is added.
I hope that people here would agree with the first method.
But using the first method, I'm having trouble displaying a page that would display all my components in my database with the 6 prices it may or may not have (should show 0 in this case). Obviously this would be simple using the second method.
This is the query I have so far:
SELECT * FROM `component` LEFT JOIN `component_cost` ON `cmpcst_component` = `cmp_id`
EDIT:
I thought I would show some sample data from the component price table:
The prices are a unit price for an amount X. X ranges from 10 to 1 million. So I might have something like this in my component price table:
id component_id type price
1 1 1 0.50
2 1 2 0.45
3 1 3 0.40
4 1 4 0.35
5 1 5 0.32
6 1 6 0.30
The first option its much better.
For display the data, create a view with a pivot table.
You can found help here
http://en.wikibooks.org/wiki/MySQL/Pivot_table
Create two tables, one for components and one for compontent's prices (for a minimum count). Then you can add as many prices per component you would like. Now and in the future.
This is a variation of your first example, you just don't hardcode types but has the number that is related to a certain price.
Try something like:
select * from component c join compcst_component cc on true and c.id = cc.cmp_id;
I'm not sure I follow you.. Hope you can give us the table structures, but here's one try:
SELECT c.cmp_id, ISNULL(p.price, 0) AS Price
FROM component AS c INNER JOI component_cost AS p
ON p.cmpcst_component = c.cmp_id
Maybe I don't have the column-to-table matchup right, but try that.

merge multiple solr facceted search into one

i have an array of products. For each product I have to crate an solr faceted search.
Example for the following "products":
Computer
TV
MP3-Player
by using faceted search I like to determine, how often every product exists in field PRODUCT.
With the following result
Comupter (3)
-apple
-ibm
-dell
TV (5)
-sony
-toshiba
[...]
MP3-player (10)
-[...]
Right now, i realize that by using one faceted search for every word/product.
That works, but the results returned in 400ms by using the following options:
'facet' => 'true'
'facet.field' => 'PRODUCT'
'facet.method' => 'enum'
'facet.limit'=>200
'facet.mincount'=>4
'fq' => 'PRODUCT:computer' <- by iterating an array with PHP i change the product (computer,tv,...) on every iteration
Unfortunately in real life there are not 3 product (like the example above), there are round about 100 products, which are relevant. That means: the PHP script hast to request 100 solr searches, with 400ms - so the script runs 40 seconds, which is to long.
I'm unable to run an unlimited/unrestricted faceted search for "all" products (without "fq="), because there are thousend of products and I dont need the information only fro a every.
Is there a way to realize a better performance for example be merge those multiple solr requests into one?
Thank you!
I didn't quite get that, but can't you just create one filter query for the products that are relevant to the query:
facet' => 'true'
'facet.field' => 'PRODUCT'
'facet.method' => 'enum'
'facet.limit'=>200
'facet.mincount'=>4
'fq' => 'PRODUCT:(computer OR tv OR mp3-player)'
And then do some processing on the returned results?
You usually don't want to filter on a specific type value when faceting. The idea behind faceting is that it will do a "group" and "count" for all values in the faceted field (for all items that matches the original query).
If you simply remove your fq-parameter you will see that in return you will get a list of all values in PRODUCT-field that occur at least 4 times and the count for each of those values.

Select records with values up to and over (but only one over) another value?

I have data such as...
ID | Amount
-----------------
1 | 50.00
2 | 40.00
3 | 15.35
4 | 70.50
etc. And I have a value I'm working up to, in this case let's say 100.00. I want to get all records up to 100.00 in order of the ID. And I want to grab one more than that, because I want to fill it up all the way to the value I'm aiming for.
That is to say, I want to get, in this example, records 1, 2, and 3. The first two total up to 90.00, and 3 pushes the total over 100.00. So I want a query to do that for me. Does such a thing exist in MySQL, or am I going to have to resort to PHP array looping?
Edit:
To put it in English terms: Let's say they have $100 in their account. I want to know which of their requests can be paid, either in toto or partially. So I can pay off the $50 and the $40, and part of the $15.35. I don't care, at this point in the program, about the partialness; I only want to find out which quality in any way.
Yes, is possible
set #total:=0;
select * from
(
select *, if(#total>100, 0, 1) as included, #total:=#total+Amount
from your_table
order by id
) as alls
where included=1
order by id;
Refering to the last sentence: doesn't mysql sum cut it?

How to Handle Consuming Lots of Data from Multiple Sources in a Web SIte

This is a "meta" question that I am asking in a effort to better understand some tough nuts I've had to crack lately. Even if you don't get precisely what I'm reaching for here or there is too much text to read through, any practical input is appreciated and probably useful.
Assume you have a website that needs to use data that is stored in multiple tables of a database. That data will need to be iterated through in a multitude of ways, used for calculations in various places, etc.
So on a page that needs to display a collection of projects (from one db table) that each contain a collection of categories (from another db table) that each contain 1 or more items (from another db table) what is the best way to gather the data, organize it and iterate through it for display?
Since each project can have 1 or more categories and each category can have one or more items (but the items are unique to a specific category) what's the best way to organize the resulting pile?
My goal in the below example is to generate a table of projects where each project has the associated categories listed with it and each category has the associated items listed with it but I also need to aggregate data from the items table to display next to the project name
A Project Name (43 items and 2 of them have errors!)
- category 1
- item 1
- item 2
- category 2
- item 1
Another Project Name (12 items and no errors)
- category 1
- item 1
- category 2
- item 1
What I did was to retrieve the data from each table and stick it in a variable. Giving me something like:
var $projects = array("id" => 1, "proj_id" => 1, "name" => "aname");
var $categories = array("id" => 1, "cat_id" => 1234, "proj_id" => 1, "cat_name" => "acatname");
var $items = array("id" => 1, "item_id" => 1234, "location" => "katmandu");
Then I went through the variables in nested foreach() loops building the rows I needed to display.
I ran into difficulties with this as the foreach() loop would work fine when building something 2 levels deep (associating categories with projects) but it did not work as expected when went three levels deep (I N C E P T I O N .. hah, couldn't resist) and tried adding the items to each category (instead adding all of them to one item... first or last I don't recall which). Also, when something was present in the third level of the array, how would you add up that data and then get it out for use back up in the top level of the array being built?
I suppose I could have constructed a mega SQL query that did it all for me and put everything into a single array, saving me the loop confusion by flattening it out, but... well, that's why I'm here asking you all.
So, I suppose the heart of this question is: How do you handle getting lots of data from different tables and then combining it all for display and use in calculations?
Sounds like you're going to want to use SQL JOINs. Consider looking into them:
http://www.w3schools.com/sql/sql_join_left.asp
They'll pull data from multiple tables and aggregate it. It won't produce quite what you're looking for, but it will produce something that you can use in a different way.
is Hadoop the sort of thing you're looking for?

Categories