Complex order by mysql - mysql

if I have a table like this
+----+----------------+
| id | id_alternativo |
+----+----------------+
| 15 | 18 |
+----+----------------+
| 16 | 0 |
+----+----------------+
| 17 | 0 |
+----+----------------+
| 18 | 0 |
+----+----------------+
How can I order records to show id 18 after id 15?

Looking at the MySQL documentation you can use multiple columns in your sort and use DESC/ASC per column.
http://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html
If I understand correctly what you mean your query will look as followed:
SELECT id, id_alternativo FROM table ORDER BY id_alternativo DESC, id DESC;
+------+----------------+
| id | id_alternativo |
+------+----------------+
| 15 | 18 |
| 18 | 0 |
| 17 | 0 |
| 16 | 0 |
+------+----------------+

One solution is to use a self join like this:
select t.*
from
yourtable t left join yourtable o
on t.id = o.id_alternativo
order by
coalesce(o.id, t.id), t.id
this will put all alternative ids after the main id (in this case 18 will follow 15).
Please see a fiddle here. Please note that this will work unless an alternative id has another alternative id (e.g. if 18 itself has another alternative id) but this cannot be solved purely with MySQL as it does not support recursive queries yet.

from what I understand just use order by id (18, 15) and any other id you need.

select id,id_alternativo
from table_name
order by case id when 15 Then 1
when 18 Then 2
when 16 Then 3
when 17 Then 4
else 5
end;

you can use order like this:
SELECT id
FROM mytab
ORDER BY IF(id=18,155,id*10);
sample
MariaDB []> select id from mytab;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
+----+
15 rows in set (0.00 sec)
MariaDB []> SELECT id
-> FROM mytab
-> ORDER BY IF(id=18,155,id*10);
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 18 |
| 16 |
| 17 |
| 19 |
+----+
15 rows in set (0.00 sec)
MariaDB []>

Sorry, I used a simple example but my table is more complex. The id_alternativo can be recursive (id 18 could have an id_alternativo = 19) and so on and id_alternativo could not be the most high id on table so ORDER BY id_alternativo DESC, id DESC doesn't work. Here's a query from my table:
SELECT
a.id, a.compatibile, a.id_alternativo
FROM
ordini_righe AS a
WHERE
intestazione IN (398010) AND a.canc = 0
AND a.stato_ordine = 0
Here's the result
+-------+-------------+----------------+
| id | compatibile | id_alternativo |
+-------+-------------+----------------+
|828924 | 0 | 828931 |
+-------+-------------+----------------+
|828925 | 828932 | 0 |
+-------+-------------+----------------+
|828926 | 0 | 0 |
+-------+-------------+----------------+
|828927 | 0 | 0 |
+-------+-------------+----------------+
|828931 | 0 | 828933 |
+-------+-------------+----------------+
|828932 | 828932 | 0 |
+-------+-------------+----------------+
|828933 | 0 | 0 |
+-------+-------------+----------------+
I had to order compatibile desc and then order the other records by the relation beetween id_alternativo and id. So i solved using a new column like this
SELECT
a.id, a.compatibile, a.id_alternativo, IF(id_alternativo = 0, a.id, id_alternativo) ordine
FROM
ordini_righe AS a
JOIN
locazioni AS b ON a.locazione = b.id
JOIN
stati_righe AS c ON a.stato_ordine = c.id
WHERE
intestazione IN (398010) AND a.canc = 0
AND a.stato_ordine = 0
ORDER BY compatibile DESC, ordine, a.id ASC
And I got the desired result
+-------+-------------+----------------+--------+
| id | compatibile | id_alternativo | ordine |
+-------+-------------+----------------+--------+
|828925 | 828932 | 828931 | 828925 |
+-------+-------------+----------------+--------+
|828932 | 828932 | 0 | 828932 |
+-------+-------------+----------------+--------+
|828926 | 0 | 0 | 828926 |
+-------+-------------+----------------+--------+
|828927 | 0 | 0 | 828927 |
+-------+-------------+----------------+--------+
|828924 | 0 | 828931 | 828931 |
+-------+-------------+----------------+--------+
|828931 | 0 | 828933 | 828933 |
+-------+-------------+----------------+--------+
|828933 | 0 | 0 | 828933 |
+-------+-------------+----------------+--------+

Related

MYSQL COUNT(column) returns multiple lines unexpectedly

I have two tables:
1. SELECT * FROM gas_trades_bids;
+----+---------+----------+--------+------------+------------+
| id | user_id | claim_id | amount | lots_value | timestmp |
+----+---------+----------+--------+------------+------------+
| 5 | 9 | 11 | 60 | NULL | 1571317861 |
| 6 | 9 | 11 | 100 | NULL | 1571656888 |
| 7 | 9 | 11 | 50 | NULL | 1571727353 |
| 8 | 9 | 11 | 50 | NULL | 1571918296 |
+----+---------+----------+--------+------------+------------+
4 rows in set (0.00 sec)
2. SELECT * FROM gas_trades_offers;
+----+---------+----------+--------+------------+----------+------------+
| id | user_id | claim_id | amount | lots_value | accepted | timestmp |
+----+---------+----------+--------+------------+----------+------------+
| 8 | 9 | 11 | 33 | 22 | NULL | 1571918576 |
| 9 | 9 | 11 | 33 | 22 | 1 | 1571918576 |
| 10 | 9 | 11 | 33 | 22 | 1 | 1571918576 |
+----+---------+----------+--------+------------+----------+------------+
3 rows in set (0.01 sec)
The goals are:
Count the amount of the rows where gas_trades_bids.claim_id = gas_trades_offers_claim_id and gas_trades_bids.claim_id = 11 and gas_trades_bids.user_id = 11
Get the sum of the column gas_trades_offers.lots_value values
To reach this I tried to run:
SELECT COUNT(bids.id) amount, SUM(offers.lots_value)
FROM gas_trades_offers offers, (SELECT * FROM gas_trades_bids) bids
WHERE bids.user_id = 9
AND bids.user_id = offers.user_id
But I've got the multiple rows:'
+--------+------------------------+
| amount | SUM(offers.lots_value) |
+--------+------------------------+
| 3 | 66 |
| 3 | 66 |
| 3 | 66 |
| 3 | 66 |
+--------+------------------------+
4 rows in set (0.01 sec)
What do I do in the wrong way?
I have expected to get only:
+--------+------------------------+
| amount | SUM(offers.lots_value) |
+--------+------------------------+
| 3 | 66 |
+--------|------------------------|
I don't need to use GROUP BY!
Is it exactly what you need? Hope that this query can work well.
SELECT COUNT(offers.id) amount,
SUM(offers.lots_value)
FROM gas_trades_offers offers
WHERE offers.user_id = 9 and offers.claim_id = 11
AND exists (SELECT id FROM gas_trades_bids bids WHERE bids.claim_id = offers.claim_id and bids.user_id = offers.user_id)
Try this:
SELECT COUNT(bids.id) amount,
SUM(offers.lots_value)
FROM gas_trades_offers offers
JOIN gas_trade_bids bids ON bids.user_id = offers.user_id
WHERE offers.user_id = 9;

I have a challenging MySQL SELECT query that involves stock and threshold bondary

I Have a MySQL DataBase which contains two tables linked with a foreign key:
MatPr(id, Designation, threshold_stock)
And
MvtStock_MatPr(id, Qte_Mvt, Qte_Tot,idMatPr)
What I want is to get the last Qte_tot, Designation,threshold_stock where threshold_stock>qte_tot
I tried this code and did not work:
SELECT MvtStock_MatPr.id,idMatPr, Nom, threshold_stock, Qte_Tot
FROM MvtStock_MatPr, MatPr
WHERE MatPr.id=MvtStock_MatPr.idMatPr AND threshold_stock>Qte_Tot
Here is Sample Data set:
mysql> SELECT MvtStock_MatPr.id,idMatPr, Designation, threshold_stock, Qte_Tot FROM MvtStock_MatPr, MatPr WHERE MatPr.id=MvtStock_MatPr.idMatPr AND threshold_stock>Qte_Tot ORDER
BY id,idMatPr;
| id | idMatPr | Dsignation| threshold_stock| Qte_Tot |
| 1 | 1 | bakra | 120 | 10 |
| 2 | 2 | zipper | 130 | 20 |
| 3 | 1 | bakra | 120 | 30 |
| 7 | 2 | zipper | 130 | 50 |
4 rows in set (0.00 sec)
mysql> SELECT * FROM MatPr;
| id | Designation| threshold_stock|
| 1 | bakra | 120 |
| 2 | zipper | 130 |
2 rows in set (0.00 sec)
mysql> SELECT * FROM MvtStock_MatPr;
| id | DateMvt | Qte_Mvt | Qte_Tot | idMatPr |
| 1 | 2016-01-01 | 10 | 10 | 1 |
| 2 | 2016-02-02 | 20 | 20 | 2 |
| 3 | 2016-03-03 | 20 | 30 | 1 |
| 4 | 2016-03-03 | 100 | 130 | 1 |
| 5 | 2016-03-03 | 50 | 180 | 1 |
| 6 | 2016-03-03 | 20 | 200 | 1 |
| 7 | 2016-03-05 | 30 | 50 | 2 |
7 rows in set (0.00 sec)
What I would like to get is:
| id | idMatPr | Dsignation| threshold_stock| Qte_Tot
| 3 | 1 | bakra | 120 | 30 |
| 7 | 2 | zipper | 130 | 50 |
+----+---------+--------+-------+---------+
Thanks for your contributions
Use the below query
Select m1.id,m1.idMatpr,m.threshold_stock,m.Qte_Tot
From MvtStock_Matpr m1 join Matpr m
On m1.idMatPr=m.id and m.threshold_stock>m1.Qte_Tot
I'm not sure that I completely follow what your problem is: is it selecting just one row from a result set? If so, does a subquery fix your problem?
SELECT *
FROM MatPr
WHERE ID = (
SELECT idMatPr
FROM MvtStock_MatPr, MatPr
WHERE MatPr.id = MvtStock_MatPr.idMatPr
AND threshold_stock > Qte_Tot
LIMIT 1
)
If you want to select just the rows from MatPr, does this work for you?
SELECT MatPr.*
FROM MvtStock_MatPr, MatPr
WHERE MatPr.id = MvtStock_MatPr.idMatPr
AND threshold_stock > Qte_Tot
http://sqlfiddle.com/#!9/d4ef50/2
Try this query:
select * from
( SELECT MvtStock_MatPr.id,idMatPr,Designation, threshold_stock, Qte_Tot
FROM MvtStock_MatPr join MatPr
on MatPr.id=MvtStock_MatPr.idMatPr
where threshold_stock>Qte_Tot
order by DateMvt desc
) T
group by T.idMatPr

SQL Query to Sort the result according to maximum common results

I have a problem in making SQL query. I am making a small Search Engine in which the word to page mapping or indexes are kept like this.
Sorry I wasn't able to post images here so I tried writing the output like this.
+---------+---------+-----------+--------+
| word_id | page_id | frequency | degree |
+---------+---------+-----------+--------+
| 2331 | 29 | 2 | 1 |
| 2332 | 29 | 7 | 1 |
| 2333 | 29 | 4 | 1 |
| 2334 | 29 | 1 | 1 |
| 2335 | 29 | 1 | 1 |
| 2336 | 29 | 1 | 1 |
| 2337 | 29 | 2 | 1 |
| 2338 | 29 | 7 | 1 |
| 2343 | 29 | 1 | 3 |
| 2344 | 29 | 1 | 3 |
......
......
...... and so on.
Word_id points to Words present in other table and page_id points to URLs present in other table.
Now Suppose I want to search "Rapid 3D Prototyping Services". I brought the union of results corresponding to individual words by query ->
select * from words_detail where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710;
In above query the word_ids corresponds to the 4 words in the search query and the results are as below.
Union of page_id corresponding to individual words...
mysql>
select * from words_detail where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710;
+---------+---------+-----------+--------+
| word_id | page_id | frequency | degree |
+---------+---------+-----------+--------+
| 2353 | 29 | 2 | 4 |
| 2353 | 33 | 2 | 2 |
| 2353 | 36 | 5 | 9 |
| 2353 | 40 | 1 | 4 |
| 2353 | 41 | 1 | 9 |
| 2353 | 45 | 4 | 9 |
| 2353 | 47 | 2 | 9 |
| 2353 | 49 | 4 | 9 |
| 2353 | 52 | 1 | 4 |
| 2353 | 53 | 1 | 9 |
| 2353 | 66 | 2 | 9 |
| 2364 | 29 | 1 | 4 |
| 2364 | 34 | 1 | 4 |
| 2364 | 36 | 9 | 2 |
| 2709 | 36 | 1 | 9 |
| 2710 | 36 | 1 | 9 |
+---------+---------+-----------+--------+
16 rows in set (0.00 sec)
But I want the result to be sorted according to maximum match. The earlier result should be where all 4 words match, next result should be with 3 match and so on. In other words earlier results should have those page_id which are common to 4 word_ids, next should be those which are common in 3 words_ids and so on.
I checked here but this is not working in my case because in my case OR conditions are not matched in a single row.
How can such a query can be designed?
Use the occurence of you page_id as your matching count and then order by it.
select * from words_detail A
inner join
(SELECT PAGE_ID
, COUNT(PAGE_ID) matchCount
from words_detail
where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710
group by PAGE_ID) B
on A.PAGE_ID=B.PAGE_ID
where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710
order by matchCount desc
Try this
select p.*
from words_detail p
, (select word_id, count(1) as count
from words_detail where
word_id in (2353,2364,2709,2710) group by word_id) t
where p.word_id = t.word_id
order by t.count desc;
You can do a subquery to get the number of apperances for each page. Then you have to join the subquery with your table and you will be able to order the results by the number of page appearances.
Your final query should look like this:
SELECT *
FROM words_detail,
(
SELECT page_id,
COUNT(*) AS npages
FROM words_detail
WHERE word_id IN (2353, 2364, 2709, 2710)
GROUP BY page_id
) AS matches
WHERE words_detail.page_id = matches.page_id
AND word_id IN (2353, 2364, 2709, 2710)
ORDER BY matches.npages DESC

mysql query for rating system

select
user_id,
#pos:=(#pos+1) as new_position,
(coins+total_item_costs) as wealth
from user_ledger
join users using (user_id),(select #pos:=0) p
ORDER BY wealth DESC
limit 10;
+---------+--------------+------------+
| user_id | new_position | wealth |
+---------+--------------+------------+
| 19 | 19 | 1112823871 |
| 11 | 11 | 13318047 |
| 8 | 8 | 7292407 |
| 6 | 6 | 6122746 |
| 27 | 27 | 5271889 |
| 23 | 23 | 5263050 |
| 9 | 9 | 5171734 |
| 3 | 3 | 5136092 |
| 15 | 15 | 5097488 |
| 4 | 4 | 5089487 |
+---------+--------------+------------+
10 rows in set (0.01 sec)
The new_position is incorrect..
What's wrong, guys? :)
ps. pls dont tell me to use temporary table
Should do the ORDER BY beforehand the position.
SELECT user_id,#pos:=(#pos+1) as new_position,wealth FROM (
select user_id,(coins+total_item_costs) as wealth from user_ledger join users
using (user_id) ORDER BY wealth DESC limit 10 ) a,(select #pos:=0) p

MySQL add extra column on result based on another query

I have following Problem
SELECT * from map_user_sticker WHERE map_user_sticker.user_id = 7;
+----+---------+------------+
| id | user_id | sticker_id |
+----+---------+------------+
| 35 | 7 | 55 |
| 3 | 7 | 30 |
| 32 | 7 | 49 |
| 33 | 7 | 52 |
| 34 | 7 | 43 |
| 36 | 7 | 50 |
+----+---------+------------+
6 rows in set (0.00 sec)
SELECT * FROM sticker;
+----+--------------------------------------------------+
| id | word |
+----+--------------------------------------------------+
| 40 | I love Sonal |
| 41 | Add User to Database |
| 39 | This is a dream Project |
| 33 | Narendra Sisodiya |
| 34 | Sourabh Parmar |
| 30 | Sonal Sisodiya |
| 42 | I love India |
| 43 | I love Linux |
| 44 | I hate Congress |
| 45 | I love jQuery |
| 48 | Modi will be the PM |
| 47 | Ramdev Baba is my Super Hero |
| 49 | हिन्दी से प्यार है |
| 50 | Linux is better then Windows |
| 52 | I am from Sehore |
| 55 | I have 2 little kids - sadu and sonu |
+----+--------------------------------------------------+
16 rows in set (0.00 sec)
I basically want to generate Result like
+----+--------------------------------------------------+----------+
| id | word | present |
+----+--------------------------------------------------+----------+
| 40 | I love Sonal | 0 |
| 41 | Add User to Database | 0 |
| 39 | This is a dream Project | 0 |
| 33 | Narendra Sisodiya | 0 |
| 34 | Sourabh Parmar | 0 |
| 30 | Sonal Sisodiya | 1 |
| 42 | I love India | 0 |
| 43 | I love Linux | 1 |
| 44 | I hate Congress | 0 |
| 45 | I love jQuery | 0 |
| 48 | Modi will be the PM | 0 |
| 47 | Ramdev Baba is my Super Hero | 0 |
| 49 | हिन्दी से प्यार है | 1 |
| 50 | Linux is better then Windows | 1 |
| 52 | I am from Sehore | 1 |
| 55 | I have 2 little kids - sadu and sonu | 1 |
+----+--------------------------------------------------+----------+
16 rows in set (0.00 sec)
Please Help me !!
I want to generate a extra column called "present", based on following condition
If sticker_id from query1 == id from query 2 then present = 1
else present = 0
Here the Answer I was wanted to get !
Answer 1 -
SELECT s.* , IF(FIND_IN_SET(7,(GROUP_CONCAT(m.user_id))) != 0 , 1,0) as present, COUNT(m.user_id) as totalUsers
FROM sticker s
LEFT JOIN map_user_sticker m
ON s.id = m.sticker_id
GROUP BY id;
Answer 2 -
SELECT id,word, (case when 7 in (select user_id from map_user_sticker WHERE map_user_sticker.sticker_id=sticker.id) then 1 else 0 end) as present
from sticker;
I don,t know which one is fast and better
Try this:
select id,word,
case(when id in (select sticker_id from map_user_sticker) then 1 else 0 end)
as present from sticker;
Hope, this will help:
SELECT sticker.id, sticker.word, (IF(sticker_id IS NULL, 0, 1)) AS present FROM sticker LEFT JOIN map_user_sticker ON (sticker.id = map_user_sticker.sticker_id)
Try this query -
SELECT s.*, IF(COUNT(m.sticker_id) > 0, 1, 0) present FROM sticker s
LEFT JOIN map_user_sticker m
ON s.id = m.sticker_id
GROUP BY
s.id;
Is this what you want?
SELECT s.*, IF(m.sticker_id IS NULL, 0, 1) present FROM sticker s
LEFT JOIN map_user_sticker m
ON s.id = m.sticker_id
WHERE m.user_id = 7;