MySQL sort by 2 parameters - mysql

I have a MySQL table with 2 fields:
pd_code and pd_sort (pd_sort default value=0). For each product it is possible to specify an order index (in pd_sort) -1000, -900 and so on.
So when I print out products in PHP, i would like to sort them out like this.
product1 (pd_sort = -100), product2 (pd_sort = -90) etc, and then the rest products (where pd_sort = 0) sorted by pd_code.
ORDER BY pd_sort,pd_code works only for 2 products.
Any suggestions?
Chris

If I understand right, you should try something like this:
SELECT * FROM table
WHERE pd_sort <> 0
ORDER BY pd_sort
UNION
SELECT * FROM table
WHERE pd_sort = 0
ORDER BY pd_code

A union as jab suggested should be fairly efficient, even if it does result in two queries rather than one.
If you don't want to do the union for whatever reason, another approach is to have the select generate a column by manipulating the pd_code and pd_sort values, and sort on that column. You haven't given us sample data to work with (well, other than a couple of pd_sort values), but in most cases it's possible to manipulate the data such that you end up with a sortable value, usually just by doing concats or numeric expressions. But in the most complex cases, you can fall back on case statements.

Related

CONCAT in WHERE clause of SELECT statement in mysql

M2014 is a text field in the DB table.
This statement works correctly (returns count = 368)
SELECT count(*) FROM arealist WHERE M2014 = 'Yes'
However, I having problems with this statement (returns count = 0) All I have changed
is the concat
SELECT count(*) FROM arealist WHERE concat('M','2014') = 'Yes'
What could be the cause and solution?
You are comparing two strings in the second SELECT statement. The second statement is appending two strings 'M' and '2014' which results in the query comparing 'M2014' to 'Yes' two strings, not the value of the column. Making a statement like this:
SELECT COUNT(*)
FROM AreaList
WHERE M2014 = CONCAT('Y','es')
That statement would return 368 rows. What are you ultimately trying to do with this statement?
You can't generate a dynamic column name for the where clause in MySQL. There are a number of Stack Overflow articles to that effect. Normally, I would arrange my data so that there was some sort of date or timestamp associated with the row, rather than using date specific columns. (I'm assuming M2014 has something to do with the year 2014). When arranged this way you can select what you need based on whatever date requirements you have.
That said, if your data model is fixed, then you're best bet is probably to use another language, C#, python, whatever, to create the column names you need dynamically and then send the entire query to MySQL. Alternatively, you could write a series of SQL statements, one for date column you're interested in.
The following query in google turned up a number of relevant results: https://www.google.com/search?client=opera&q=dynamic+column+names+in+sql&sourceid=opera&ie=utf-8&oe=utf-8&channel=suggest&safe=active#channel=suggest&q=dynamic+column+names+in+mysql+where+clause&safe=active
you can do it in php like that
$year = 2014;
SELECT count(*) FROM arealist
WHERE M$year = 'Yes'

Learning SQL: UNION or JOIN?

Forgive me if this seems like common sense as I am still learning how to split my data between multiple tables.
Basically, I have two:
general with the fields userID,owner,server,name
count with the fields userID,posts,topics
I wish to fetch the data from them and cannot decide how I should do it: in a UNION:
SELECT `userID`, `owner`, `server`, `name`
FROM `english`.`general`
WHERE `userID` = 54 LIMIT 1
UNION
SELECT `posts`, `topics`
FROM `english`.`count`
WHERE `userID` = 54 LIMIT 1
Or a JOIN:
SELECT `general`.`userID`, `general`.`owner`, `general`.`server`,
`general`.`name`, `count`.`posts`, `count`.`topics`
FROM `english`.`general`
JOIN `english`.`count` ON
`general`.`userID`=`count`.`userID` AND `general`.`userID`=54
LIMIT 1
Which do you think would be the more efficient way and why? Or perhaps both are too messy to begin with?
It's not about efficiency, but about how they work.
UNION just unions 2 different independent queries. So you get 2 result sets one after another.
JOIN appends each row from one result set to each row from another result set. So in total result set you have "long" rows (in terms of amount of columns)
Just for completeness as I don't think it's mentioned elsewhere: often UNION ALL is what's intended when people use UNION.
UNION will remove duplicates (so relatively expensive because it requires a sort). This remove duplicates in the final result (so it doesn't matter if there's a duplicate in a single query or the same data from individual SELECTs). UNION is a set operation.
UNION ALL just sticks the results together: no sorting, no duplicate removal. This is going to be quicker (or at least no worse) than UNION.
If you know the individual queries won't return duplicate results use UNION ALL. (In fact often best to assume UNION ALL and think about UNION if you need that behaviour; using SELECT DISTINCT with UNION is redundant).
You want to use a JOIN. Joining is used to creating a single set which is a combination of related data. Your union example doesn't make sense (and probably won't run). UNION is for linking two result sets with identical columns to create a set that has the combined rows (it does not 'union' the columns.)
If you want to fetch users and near user posts and topics. you need to write QUERY using JOIN like this:
SELECT general.*,count.posts,count.topics FROM general LEFT JOIN count ON general.userID=count.userID

MySQL how to safely randomize the output of this query?

I have a SELECT query that I am expecting millions of results from. I need to randomize these results in MySQL. Doing it in my script after the query obviously uses too much RAM. Can someone please rework this query so that the results are all random without using order by rand()? I have seen some examples and tried to use them but they don't work for me since they all seem to depend on returning the whole table rather than using a WHERE clause. Here is my query:
SELECT * FROM pool
WHERE gender = 'f'
AND (`location` = 'united states' OR `location` = 'us' OR `location` = 'usa');
If you have 10 million lines with id's, are they in a contiguous range?
Get the lowest id from the range you want via a quick select.
Get the largest id as well.
generate random numbers in this range using php
once you have your numbers "SELECT * FROM table1 WHERE id IN (the numbers you generated)" or something like that
If you can use other language, for example php you can use its rand() function to generate ids and add the to the query like
$ids = range($mini, $maxid);
shuffle($ids);
array_slice($ids, 0, $quantity);
Or something similar in any language you are using.
If you need to do this in pure mysql query then here are some alternaties: http://www.electrictoolbox.com/msyql-alternative-order-by-rand/

Best way to combine multiple advanced mysql select queries

I have multiple select statements from different tables on the same database. I was using multiple, separate queries then loading to my array and sorting (again, after ordering in query).
I would like to combine into one statement to speed up results and make it easier to "load more" (see bottom).
Each query uses SELECT, LEFT JOIN, WHERE and ORDER BY commands which are not the same for each table.
I may not need order by in each statement, but I want the end result, ultimately, to be ordered by a field representing a time (not necessarily the same field name across all tables).
I would want to limit total query results to a number, in my case 100.
I then use a loop through results and for each row I test if OBJECTNAME_ID (ie; comment_id, event_id, upload_id) isset then LOAD_WHATEVER_OBJECT which takes the row and pushes data into an array.
I won't have to sort the array afterwards because it was loaded in order via mysql.
Later in the app, I will "load more" by skipping the first 100, 200 or whatever page*100 is and limit by 100 again with the same query.
The end result from the database would pref look like "this":
RESULT - selected fields from a table - field to sort on is greatest
RESULT - selected fields from a possibly different table - field to sort on is next greatest
RESULT - selected fields from a possibly different table table - field to sort on is third greatest
etc, etc
I see a lot of simpler combined statements, but nothing quite like this.
Any help would be GREATLY appreciated.
easiest way might be a UNION here ( http://dev.mysql.com/doc/refman/5.0/en/union.html ):
(SELECT a,b,c FROM t1)
UNION
(SELECT d AS a, e AS b, f AS c FROM t2)
ORDER BY a DESC

mysql IF Else Statement

Not sure how far a sql query can go with if/else statements.
I have a simple SELECT statement:
SELECT amount, transtype FROM
transactions
The transtype column is going to be a number.
For example, 1 = sale, 2 = refund, 3 = error, 4 = canceled, 5 = something else.... and so on.
So, nothing complicated. But the list tends to grow for reporting reasons. Which is fine.
For a specific query I'm working on, is there a way to extract that column as one of 2 or three specified numbers or text?
For example, some transtype numbers are a 'loss', while others are a 'gain', and maybe others are 'neutral'.
I'd like to extract that column with only those 3, without using php inside the html table I'm throwing the rows into.
If my explanation is not clear, my apologies. It was hard to spit out.
Use the MySQL CASE() function for a fixed number of arguments. If the list is getting big, you should use a second table and join them.
Example:
SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END;
Try joining against another table that contains the transaction types. Something like:
TRANSACTION_TYPES
transtype | number
label | varchar(32)
Then modify your query to include the join:
select t.amount, t.transtype, l.label
from transactions.t
join transaction_types l on t.transtype = l.transtype;
The ELT function should do the trick:
SELECT ELT(`transtype`, 'loss', 'loss', 'gain', 'neutral', …) FROM …
Not very elegant though, and logically I would do this in the view logic, not the database logic.
You should probably use ENUM type for that column. It's limited to 64 values, however if you would need more then you should create a new table and JOIN it in query.