Order by multiple columns from 2 tables - mysql

I want to make merge 2 tables, and then do ORDER BY, first to order them by top column, so that products with value 1 in top show up first in record set.
Afterwards, I want to order them by premium column, so that products with value 1 go right after top products.
After that, I want the rest of products to order by pub_date from table items, and products with value 1 in column highlighted should not be shown directly bellow top and premium items.
Since original tables are full of unnecessary info, here's the stripped down versions:
Table `items`:
+-------+------------+--------+
| pk_id | pub_date | author |
+-------+------------+--------+
| 1 | 2013-06-11 | John |
| 2 | 2013-06-12 | Mike |
| 3 | 2013-06-25 | Seth |
| 4 | 2013-06-11 | Drew |
| 5 | 2013-06-13 | Joe |
+-------+------------+--------+
Table `paid_items`:
+-------+-----+---------+-------------+--------+
| fk_id | top | premium | highlighted | active |
+-------+-----+---------+-------------+--------+
| 2 | 1 | 0 | 0 | 1 |
| 3 | 0 | 0 | 1 | 1 |
| 4 | 0 | 1 | 0 | 1 |
| 5 | 0 | 0 | 1 | 1 |
+-------+-----+---------+-------------+--------+
EDIT:
Here's the pseudo (or whatever) of what I want to accomplish:
PRODUCTS_LIST>
PRODUCTS WITH TOP VALUE
PRODUCTS WITH PREMIUM VALUE
PRODUCTS ORDERED BY PUB_DATE>
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH HIGHLIGHTED VALUE
PRODUCT WITH NO HIGHLIGHTED VALUE
PRODUCT WITH HIGHLIGHTED VALUE
...
A striped down version of how the recordset should look like, focus is on highlighted column:
mysql> select pk_id, highlighted from items left join paid_items on items.pk_id
= paid_items.fk_id order by pub_date desc;
+-------+-------------+
| pk_id | highlighted |
+-------+-------------+
| 3 | 1 |
| 5 | 1 |
| 2 | 0 |
| 1 | NULL |
| 4 | 0 |
+-------+-------------+

Simple select would be:-
SELECT *
FROM items a
LEFT OUTER JOIN paid_items b
ON a.pk_id = b.fk_id
ORDER BY b.top, b.premium, a.pub_date
but I presume you know that already.
However I am unsure what you mean by products with value 1 in column highlighted should not be shown directly bellow top and premium items . Do you want these excluded, or displayed at the bottom of the list. Could you put some example output in your question?

Related

Automatically inserting additional columns in MySQL 8.0 [duplicate]

This question already has an answer here:
MySQL pivot row into dynamic number of columns
(1 answer)
Closed 3 years ago.
Say I have a table like so
+----+----------+------+
| id | name | type |
+----+----------+------+
| 1 | apple | F |
| 1 | pear | F |
| 1 | cucumber | V |
| 2 | orange | F |
| 2 | grass | NULL |
| 2 | broccoli | V |
| 3 | flower | NULL |
| 3 | tomato | NULL |
+----+----------+------+
I want to end up with a table that counts the number of elements for each type (including NULL types) AND for each id, like this:
+----+-----------------+--------------+--------------+
| id | type_NULL_count | type_F_count | type_V_count |
+----+-----------------+--------------+--------------+
| 1 | 0 | 2 | 1 |
| 2 | 1 | 1 | 1 |
| 3 | 2 | 0 | 0 |
+----+-----------------+--------------+--------------+
This is rather easy to do, but is there a way (a query I can write or something else) such that when I go back and edit one of the type fields in the first table, I end up with a properly updated count table?
For example, let's say I want to add a new type (type X) and change the type field for flower from NULL to X. Is there a way to end up with the following table without having to rewrite the query or add more statements?
+----+-----------------+--------------+--------------+--------------+
| id | type_NULL_count | type_F_count | type_V_count | type_X_count |
+----+-----------------+--------------+--------------+--------------+
| 1 | 0 | 2 | 1 | 0 |
| 2 | 1 | 1 | 1 | 0 |
| 3 | 1 | 0 | 0 | 1 |
+----+-----------------+--------------+--------------+--------------+
I'm not sure if this is the best way to do this, so I am open to suggestions
Having a secondary table which it's number of columns changes based on your first table is not a viable option.
Do you need to keep the result in a table or it will be displayed as a report?
I think a better way to do this is using the SQL below calculate counts by id plus type and display using your data display tool the way you like it.
select id, type, count(*) count
from d
group by 1,2
order by 1,2
The output would be
id type count
1 F 2
1 V 1
2 F 1
2 V 1
2 1
3 X 1
3 1

SELECT, how to combine some rows as one, show rows with specific column value first and exclude a row

I have two tables, units and power.
Take a look at:
The power table:
+----+-------+
| id | power |
+----+-------+
| 1 | 2 |
| 2 | 4 |
| 3 | 6 |
| 4 | 8 |
+----+-------+
The units table:
+----+---------+----------+--------+----------+---+---+
| id | user_id | power_id | amount | group_id | x | y |
+----+---------+----------+--------+----------+---+---+
| 1 | 10 | 3 | 1000 | 0 | 1 | 1 |
| 2 | 10 | 3 | 1000 | 0 | 1 | 1 |
| 3 | 10 | 3 | 1000 | 0 | 1 | 1 |
| 4 | 11 | 2 | 100 | 4 | 1 | 1 |
| 5 | 11 | 2 | 100 | 4 | 1 | 1 |
| 6 | 11 | 1 | 100 | 4 | 1 | 1 |
| 7 | 12 | 4 | 1000 | 0 | 1 | 1 |
+----+---------+----------+--------+----------+---+---+
I want to get result looking like this:
+----------+--------------+-------------+----------+---------+--+
| units.id | total_amount | total_power | group_id | user_id | |
+----------+--------------+-------------+----------+---------+--+
| 3 | 1000 | 6000 | 0 | 10 | |
| 2 | 1000 | 6000 | 0 | 10 | |
| 4 | 300 | 1000 | 4 | 11 | |
| 7 | 1000 | 8000 | 0 | 12 | |
+----------+--------------+-------------+----------+---------+--+
Explanation:
Exclude a specific id, should work same for both a single row and a row which is a sum of multiple rows in the table. As you see, in the result set, row with id 1 was excluded. The id is provided by the app, I think it's better to do it in MySQL than PHP, because MySQL could just discard this row (I think), but with PHP it would have to do if() checking for every loop iteration, which seems less efficient.
Show the summed-rows row before single rows, every time.
Show user's units before other users', every time. You can see that when rows with user_id of 10 (imagine this user is the one seeing the page) appear first in my result set.
Show units with highest power first.
Show units with highest amount first.
Show units with highest id first.
The last(4.5.6) are sorted in regards to the priority of the result set, with 4th having the most of it.
I have this query:
SELECT units.id,
units.amount*power.power AS total_power,
Sum(units.amount) AS total_amount
FROM units
JOIN power
ON units.power_id = power.id
WHERE x = ?
AND y = 1
GROUP BY group_id
ORDER BY group_id desc, total_power desc, total_amount desc, units.id desc limit ?,?
But it combines all units where group_id is 0, however I want units with group_id=0 to be separate rows in the result set. How to do that? Thanks!
Edit: To answer #Linoff's question about how I determine which id to exclude, I exclude the 1 in the example because a user always will see the result set through accessing it with a unit_id, which, again, in my example happens to be 1. I hope it is clear now.
Edit: The user can access this list of units on page "index.php?page=unit/view&id=. Then I SELECT the entered id separately for the purpose of my app, and then SELECT the list. But as I already have data for the entered id (for instance, 1 in this case) I do not need to have them when I SELECT from the units and power.
#Anonymous, to answer your question 1, answer 1 is: all rows with same group_id (except 0 which is a not-a-group marker) are grouped and combined together, so rows which are id 4,5 and 6 which have identical group_id are combined. My problem is, I don't know how to exclude grouping for rows which are stand alone (no group marking) and how to sort the result so the rows with specified user_id are sorted first and grouped rows (4,5,6-turned-to-4) are also sorted first, but in user_id=10-first,user_id=??-second hierarchy, if this makes sense.

Show rows from another tables if exist (SQL)

I want to show data that a user can modify. If the user do changes, i like keeping the original data in my database.
When a user get data, he should view the data modified.
(Much users can modiffied data).
For example:
Products (non editable for users)
ID | Name | Color
----------------------
1 | Apples | Yellow
2 | Pears | Green
3 | Lemons | Yellow
ModProducts (one row for modified product and user)
SourceID | UserID | Name | Color
-------------------------------------------
1 | 3 | RedApples | Red
1 | 4 | Sminth Apples | Green
Result for UserID 3:
ID | Name | Color
-------------------------
1 | RedApples | Red
2 | Pears | Green
3 | Lemons | Yellow
I tryed with COALESCE, CASE but i canĀ“t filter by UserID.
I Also tryed with GROUP BY, putting all data in same table, but I have not managed to give priority to the modified data
I'm going crazy..
Maybe you're designing the data model wrong?
You probably just misplaced the UserID filter. The filter on UserID has to be part of the outer join condition it can not be in the where clause. Try the following select:
select p.id,
coalesce(m.name, p.name) name,
coalesce(m.color, p.color) color
from products p
left join modproducts m on m.id = p.id and
m.userid = 3
Problem solved in one table
Table Products
ID | Ref | UserID | Name | Color
-------------------------------------------
1 | 1 | 0 | Apples | Yellow
2 | 2 | 0 | Strawberrys | Red
3 | 3 | 0 | Lemons | Yellow
4 | 1 | 2 | Apples | Green
5 | 1 | 3 | MiniApples | Green
I like this result
ID | Ref | UserID | Name | Color
-------------------------------------------
4 | 1 | 2 | Apples | Green
2 | 2 | 0 | Strawberrys | Red
3 | 3 | 0 | Lemons | Yellow
I resolv this form:
SELECT *
FROM ( SELECT * FROM Products ORDER BY Ref, UserID DESC) AS Prod
WHERE UserID = 2
OR UserID = 0
GROUP BY Ref

mysql select to give all rows of one column that match any row of another?

+-----------------+-----------+-------+-------------+
| orders_total_id | orders_id | value | class |
+-----------------+-----------+-------+-------------+
| 1 | 1 | 34.00 | ot_subtotal |
| 2 | 1 | 8.56 | ot_shipping |
| 3 | 1 | 2.38 | ot_tax |
| 4 | 1 | 0.600 | ot_tax |
| 5 | 2 | 45.54 | ot_subtotal |
| 6 | 2 | 8.56 | ot_shipping |
+-----------------+-----------+-------+-------------+
I want to show ALL the records that belong to ANY rows which also have a row that has class=ot_tax. So in the above, rows 1-4 would match because one (or more) of them have a class of ot_tax and they all have the same orders_id, but NOT rows 5-6 because they also have same orders_id but none have class=ot_tax.
I want to say the key here has to do with grouping, but SQL syntax still feels so foreign to me. Thanks.
So you want to get all orders that have a row with class='ot_tax' ?
There are several ways, for instance using the in predicate:
SELECT * FROM table_name
WHERE orders_id IN (SELECT orders_id FROM table_name WHERE class='ot_tax')

Most frequent values by two columns SQL

I am trying to figure out the most occurring values within a table in groups.
This is for SQL
Part | location | PartDesc
-----+----------+-------------
A | 2 | Part A
A | 2 | Part A
A | 2 | Part A
A | 1 | Part A
A | 1 | Part A
B | 1 | Part B
B | 2 | Part B
So the output needs to show
Part | Location | PartDesc | Occurrence
-----+----------+----------+--------------
A | 2 | Part A | 3
A | 1 | Part A | 2
B | 1 | Part B | 1
B | 2 | Part B | 1
So far I have
Select Part, count(*) as occurrence
from table1
group by Part
order by count(*desc)
SELECT
Part,
Location,
PartDesc,
COUNT(*) AS Occurrence
FROM
table1
GROUP BY
Part,
Location,
PartDesc
ORDER BY
Occurrence DESC
Thanks.