In reference with my previous question - how to get a sorted result in mysql query?
I am trying to get a sorted result of a table from a MySQL query.
The Table without sorting is as follows :
+---------+---------------+
| id | cat_type |
+---------+---------------+
| 1 | free |
| 2 | free |
| 3 | free |
| 4 | paid |
| 5 | paid |
| 6 | free |
| 7 | free |
| 8 | free |
| 9 | paid |
| 10 | free |
| 11 | free |
| 12 | free |
| 13 | paid |
| 14 | free |
+---------+---------------+
The Sorted Table must be as follows :
+---------+---------------+
| id | cat_type |
+---------+---------------+
| 1 | free |
| 2 | free |
| 4 | paid |
| 3 | free |
| 6 | free |
| 5 | paid |
| 7 | free |
| 8 | free |
| 9 | paid |
| 10 | free |
| 11 | free |
| 13 | paid |
| 12 | free |
| 14 | free |
+---------+---------------+
TASK : All the records are seperated by 3 for clarity and it should be sorted by column cat_type and not by id. The cat_type must be ordered by free, free and paid(Refer 2nd table column records.)
NOTE : The table is dynamic and has 'n' number of records.
How can i accomplish this with a mysql query ?
You can enumerate the rows for free and paid. Probably the easiest way to enumerate two categories is with union all. Then you can do arithmetic to get the "free" records first, and then the "paid" records. I think this will do it:
select id, cat_type
from ((select t.*, #rn1 := #rn1 + 1 as seqnum
from table t cross join (select #rn1 := 0) vars
where cat_type = 'free'
order by id
) union all
(select t.*, #rn2 := #rn2 + 1 as seqnum
from table t cross join (select #rn2 := 0) vars
where cat_type = 'paid'
order by id
)
) t
order by (case when cat_type = 'free' then seqnum*1.0 else 2 * seqnum + 0.5 end)
I got an answer for my question and it works well for me.
The following code did the trick :
SET #i := 0;
SET #j := 0.5;
SELECT id, cat_type FROM
(SELECT #i := #i + 1 as ordering, id, cat_type FROM table_name WHERE cat_type = 'free'
UNION
SELECT #j := #j + 2 as ordering, id, cat_type FROM table_name WHERE cat_type = 'paid')
AS base_table
ORDER BY ordering;
Works like charm. Thanks for the answers.
Related
I have the database as below, i need to get all the zeros and ones in separate list from the below table, that is to get all the zero together in a column and all the ones together in separate column
database
| id | value |
-------------
| 1 | 0 |
| 2 | 1 |
| 3 | 0 |
| 4 | 1 |
expected result
| sp.id | stop | st.id | start|
-------------------------------
| 1 | 0 | 2 | 1 |
| 3 | 0 | 4 | 1 |
or
| id | value |
-------------
| 1 | 0 |
| 3 | 0 |
| id | value |
-------------
| 2 | 1 |
| 4 | 1 |
SELECT a.id AS sp.id, a.value AS stop, b.id AS st.id, b.value AS start
FROM (SELECT * FROM TABLE WHERE = 0) a
LEFT JOIN (SELECT * FROM TABLE WHERE = 1) b
ON a.id = b.id
UNION
SELECT a.id AS sp.id, a.value AS stop, b.id AS st.id, b.value AS start
FROM (SELECT * FROM TABLE WHERE = 0) a
RIGHT JOIN (SELECT * FROM TABLE WHERE = 1) b
ON a.id = b.id
For your expected result 1, you can use case
select case when value=0 then id end as spid,
case when value=0 then value end as stop,
case when value=1 then id end as stid,
case when value=1 then value end as start
from yourtable.
But you will get NULL for empty rows as shown below. If that is fine, you can use the above query. If it is a String you can use MAX() or MIN() with group by to avoid this empty values.
OUTPUT
+------+------+------+-------+
| spid | stop | stid | start |
+------+------+------+-------+
| 1 | 0 | | |
+------+------+------+-------+
| | | 2 | 1 |
+------+------+------+-------+
| 3 | 0 | | |
+------+------+------+-------+
| | | 4 | 1 |
+------+------+------+-------+
For you expected output 2, you can directly use UNION ALL
select id,value from test where value=0
union all
select id,value from test where value=1
OUTPUT
+----+-------+
| id | value |
+----+-------+
| 1 | 0 |
+----+-------+
| 3 | 0 |
+----+-------+
| 2 | 1 |
+----+-------+
| 4 | 1 |
+----+-------+
CHECK DEMO HERE
I want to get the categories pricing, Say if there is data in customer_category_pricing table then fetch that pricing for that specific customer. Otherwise fetch default prices from categories table.
i have tried achieving this desired result using mysql case it is working fine, but the problem is, it is returning two rows
hourly_amount_final column returns updated price then per_day_amount_final returns default price
Then in next row, hourly_amount_final column return default price and then per_day_amount_final returns updated price.
table: pr_categories
---------------------------------------------------------------------------------
| id | title | hourly_amount | per_day_amount | created_at| updated_at
---------------------------------------------------------------------------------
| 1 | Power Generation | 100.00 | 200.00 |
| 2 | Local Government | 300.00 | 400.00 |
----------------------------------------------------------
table: pr_customer_categories_pricing
------------------------------------------------------------------------------------
| id | customer_id | category_id | billing_type_id | amount | created_at | updated_at
------------------------------------------------------------------------------------
| 1 | 1 | 1 | 1 | 109 |
| 2 | 1 | 1 | 2 | 600 |
----------------------------------------------------------
table: pr_billing_types
----------------
| id | title |
--------------
| 1 | Hourly |
| 2 | Per Day |
----------------
This is the query i am working with at the moment:
SELECT c.id,c.title,
CASE
WHEN (c.hourly_amount <> (SELECT ccp.amount WHERE ccp.billing_type_id = 1))
THEN (SELECT ccp.amount WHERE ccp.billing_type_id = 1)
ELSE c.hourly_amount
END
AS hourly_amount_final,
CASE
WHEN (c.per_day_amount <> (SELECT ccp.amount WHERE ccp.billing_type_id = 2))
THEN (SELECT ccp.amount WHERE ccp.billing_type_id = 2)
ELSE c.per_day_amount
END
AS per_day_amount_final
FROM pr_customer_category_pricing AS ccp
RIGHT JOIN pr_categories AS c
ON c.id = ccp.category_id AND ccp.customer_id = 1
Expected result when there is no data in pr_customer_category_pricing
----------------------------------------------------------------------
| id | title | hourly_amount_final | per_day_amount_final |
----------------------------------------------------------------------
| 1 | Power Generation | 100.00 | 200.00 |
| 2 | Local Government | 300.00 | 600.00 |
----------------------------------------------------------------------
Expected result when there is data in pr_customer_category_pricing
----------------------------------------------------------------------
| id | title | hourly_amount_final | per_day_amount_final |
----------------------------------------------------------------------
| 1 | Power Generation | 109.00 | 600.00 |
| 2 | Local Government | 300.00 | 400.00 |
----------------------------------------------------------------------
Actual result what i'm getting:
----------------------------------------------------------------------
| id | title | hourly_amount_final | per_day_amount_final |
----------------------------------------------------------------------
| 1 | Power Generation | 109.00 | 200.00 |
| 1 | Power Generation | 100.00 | 600.00 |
| 2 | Local Government | 300.00 | 400.00 |
----------------------------------------------------------------------
What am i doing wrong? Any suggestions! Help a brother out. :S
Since there can only be one entry in the pr_customer_category_pricing table per billing type, you can simplify things by creating a derived pivot table from the pr_customer_category_pricing with values for each of the billing_type_id in separate columns. You can then simply COALESCE the value from the derived table with the value from the pr_categories for each billing_type_id:
SELECT c.id,c.title,
COALESCE(ccp.hourly_amount, c.hourly_amount) AS hourly_amount_final,
COALESCE(ccp.per_day_amount, c.per_day_amount) AS per_day_amount_final
FROM (SELECT
customer_id,
category_id,
MAX(CASE WHEN billing_type_id = 1 THEN amount END) AS hourly_amount,
MAX(CASE WHEN billing_type_id = 2 THEN amount END) AS per_day_amount
FROM pr_customer_category_pricing
GROUP BY customer_id, category_id) AS ccp
RIGHT JOIN pr_categories AS c
ON c.id = ccp.category_id AND ccp.customer_id = 1
Output:
id title hourly_amount_final per_day_amount_final
1 Power Generation 109 600
2 Local Government 300 400
Demo on dbfiddle
You can use max() aggregation with group by
SELECT c.id,c.title,
max(CASE
WHEN (c.hourly_amount <> (SELECT ccp.amount WHERE ccp.billing_type_id = 1))
THEN (SELECT ccp.amount WHERE ccp.billing_type_id = 1)
ELSE c.hourly_amount
END)
AS hourly_amount_final,
max(CASE
WHEN (c.per_day_amount <> (SELECT ccp.amount WHERE ccp.billing_type_id = 2))
THEN (SELECT ccp.amount WHERE ccp.billing_type_id = 2)
ELSE c.per_day_amount
END)
AS per_day_amount_final
FROM pr_customer_category_pricing AS ccp
RIGHT JOIN pr_categories AS c
ON c.id = ccp.category_id AND ccp.customer_id = 1
group by c.id,c.title
I have the following 2 MySQL tables:
players:
| id | name |
|----|---------|
| 1 | Player1 |
| 2 | Player2 |
| 3 | Player3 |
scores:
| key | id | round | score |
|-----|----|-------|-------|
| 1 | 1 | Rd1 | 20 |
| 2 | 1 | Rd2 | 22 |
| 3 | 1 | Rd3 | 19 |
| 4 | 2 | Rd1 | 18 |
| 5 | 2 | Rd2 | 23 |
| 6 | 2 | Rd3 | 19 |
where scores.id=players.id
I will have upwards of 90 players in my 'players' table, what's the best way to query this and insert it into an HTML table to make it easier to view? I'm hoping to have an output similar to this:
| Player | Round 1 | Round 2 | Round 3 |
|---------|---------|---------|---------|
| Player1 | 20 | 22 | 19 |
| Player2 | 18 | 23 | 19 |
This is my first attempt at normalizing data in tables. Am I going to have to do number of cases? I'm not sure what the best way to pivot the data is with an INNER JOIN.
This is my solution, hope it helps :
SELECT
name as Player,
SUM(CASE WHEN (s.round='Rd1') THEN s.score ELSE 0 END) AS Round1,
SUM(CASE WHEN (s.round='Rd2') THEN s.score ELSE 0 END) AS Round2,
SUM(CASE WHEN (s.round='Rd3') THEN s.score ELSE 0 END) AS Round3
FROM
players p
JOIN scores s
on s.id=p.id
GROUP BY
name
This will output :
| Player | Round1 | Round2 | Round3 |
|---------|---------|---------|---------|
| Player1 | 20 | 22 | 19 |
| Player2 | 18 | 23 | 19 |
This Fiddle for you to test!
I have a sligthly alternative solution which uses subqueries with the following benefit that players with no no score gets listed too!!
SELECT
p.name,
ifnull((select score from scores where id = p.id and round='Rd1' limit 1), 0) as Round1,
ifnull((select score from scores where id = p.id and round='Rd2' limit 1), 0) as Round2,
ifnull((select score from scores where id = p.id and round='Rd3' limit 1), 0) as Round3
FROM players p
GROUP BY p.name, p.id
Well I have a table(MYSQL) 'product', with one of the columns named 'category_id' that stores category id from another table 'category' . So there are multiple categories in 'category_id' column. eg table below. Now I want to select fixed number of product from each category(say 2), for eg i want to select 2 latest products from each category from the product table. What mysql query should i use, any idea?
Product:
+-------------+------+---------------------+
| category_id | name | timestamp |
+-------------+------+---------------------+
| 1 | abc | 2016-02-27 16:04:00 |
| 1 | def | 2016-02-28 16:10:00 |
| 1 | ghi | 2016-02-29 16:11:00 |
| 2 | pqr | 2016-02-27 16:04:00 |
| 2 | stu | 2016-02-27 16:05:00 |
| 3 | vwx | 2016-02-28 16:04:00 |
+-------------+------+---------------------+
Expected Result:
Product:
+-------------+------+---------------------+
| category_id | name | timestamp |
+-------------+------+---------------------+
| 1 | def | 2016-02-28 16:10:00 |
| 1 | ghi | 2016-02-29 16:11:00 |
| 2 | pqr | 2016-02-27 16:04:00 |
| 2 | stu | 2016-02-27 16:05:00 |
| 3 | vwx | 2016-02-28 16:04:00 |
+-------------+------+---------------------+
It may help you...
Check the Output in SQL Fiddle Link: http://sqlfiddle.com/#!9/3942d2/6
SELECT
category_id,
name,
tsDate
FROM
(
SELECT
category_id,
name,
tsDate,
#rn := IF(#prev = category_id, #rn + 1, 1) AS rn,
#prev := category_id
FROM Product
JOIN (SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY category_id, tsDate DESC, name
) AS T1
WHERE rn <= 2
Try this :
SELECT x.*
FROM my_table x
JOIN my_table y
ON y.category_id = x.category_id
AND y.timestamp >= x.timestamp
GROUP
BY x.category_id,x.timestamp
HAVING COUNT(*) <= 2;
I need help to get the solution for this condition. I have a table containing records, there is a field sku, in this record i have sku's appearing multiple times. Table structure is like this rid|id|sku|name
if any sku is available on table multiple times the record looks like this
rid id sku name
--- -- ------ --------------
1 3 rs-123 test product
2 3 rs-123 test product
3 4 rs-125 test product 2
4 4 rs-125 test product 2
5 4 rs-125 test product 2
6 6 rs-126 test product 3
What I need is to update the table with duplicate records keeping first record unchanged (N-1). So for example I need to run SQL statement which update only duplicate records, so if first record is updated it will look like this
rid id sku name
--- -- ------ --------------
1 3 rs-123 test product
2 3 updated updated
I was trying to achieve something with this SQL statement but it is not working
WITH duplicates AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY id ORDER BY rid) AS duplicate_id,
*
FROM
test
)
UPDATE
duplicates
SET
sku = updated
WHERE
duplicate_id > 1
Any advise would be highly appreciated.
Perhaps you may give it a try with a variable:
SQLFIDDLE DEMO
set #sku:='';
select a.rid, a.id,
#sku:= (case when #sku<>a.sku
then a.sku else 'updated'
end) as skus, #sku:=a.sku, a.name
from skus a
;
| RID | ID | SKUS | #SKU:=A.SKU | NAME |
-----------------------------------------------------
| 1 | 3 | rs-123 | rs-123 | test product |
| 2 | 3 | updated | rs-123 | test product |
| 3 | 4 | rs-125 | rs-125 | test product 2 |
| 4 | 4 | updated | rs-125 | test product 2 |
| 5 | 4 | updated | rs-125 | test product 2 |
| 6 | 6 | rs-126 | rs-126 | test product 3 |
For updating:
SQLFIDDLE DEMO for UPDATING
set #sku:='';
UPDATE
skus a
join
(select a.rid, a.id,
#sku:= (case when #sku<>a.sku
then a.sku else 'updated'
end) as skus, #sku:=a.sku, a.name
from skus a) b
on a.rid = b.rid
SET
a.sku = 'up_again'
WHERE
b.skus = 'updated'
;
| RID | ID | SKU | NAME |
----------------------------------------
| 1 | 3 | rs-123 | test product |
| 2 | 3 | up_again | test product |
| 3 | 4 | rs-125 | test product 2 |
| 4 | 4 | up_again | test product 2 |
| 5 | 4 | up_again | test product 2 |
| 6 | 6 | rs-126 | test product 3 |
Here is another using Joins:
http://sqlfiddle.com/#!2/ddf47/2
update skus a
join skus b
on a.rid = b.rid +1
set a.sku = 'updated'
where a.sku = b.sku
;
| RID | ID | SKU | NAME |
---------------------------------------
| 1 | 3 | rs-123 | test product |
| 2 | 3 | updated | test product |
| 3 | 4 | rs-125 | test product 2 |
| 4 | 4 | updated | test product 2 |
| 5 | 4 | updated | test product 2 |
| 6 | 6 | rs-126 | test product 3 |
To update both sku and name:
http://sqlfiddle.com/#!2/97f4f/1
update skus a
join skus b
on a.rid = b.rid +1
set a.sku = 'updated', a.name = 'new_name'
where a.sku = b.sku
;
| RID | ID | SKU | NAME |
---------------------------------------
| 1 | 3 | rs-123 | test product |
| 2 | 3 | updated | new_name |
| 3 | 4 | rs-125 | test product 2 |
| 4 | 4 | updated | new_name |
| 5 | 4 | updated | new_name |
| 6 | 6 | rs-126 | test product 3 |
LOOKING AT OP'S QUESTION having used ROW_NUMBER() IN SQL SERVER
http://sqlfiddle.com/#!3/355c4/2
update a
set a.sku = 'updated', a.name = 'new_name'
from skus a
join (Select rid, id, row_number() over (
partition by id order by rid asc) rank
from skus) b
on a.rid = b.rid
where b.rank > 1
;
| RID | ID | SKU | NAME |
---------------------------------------
| 1 | 3 | rs-123 | test product |
| 2 | 3 | updated | new_name |
| 3 | 4 | rs-125 | test product 2 |
| 4 | 4 | updated | new_name |
| 5 | 4 | updated | new_name |
| 6 | 6 | rs-126 | test product 3 |
Try this:
UPDATE
test
SET
sku = 'updatedSKU'
WHERE rid IN
(
SELECT
rid
FROM
(
SELECT rid,
#rn := IF(#sku != sku, 1, #rn + 1) rn,
#sku:=sku
FROM test,
(SELECT #rn:=0, #sku := NULL) r
) s
WHERE rn > 1
);
SQL FIDDLE DEMO
or this:
UPDATE
test t
JOIN
(
SELECT rid,
CASE WHEN #sku != sku THEN #rn := 1 ELSE #rn := #rn + 1 END rn,
#sku:=sku
FROM test,
(SELECT #rn:=0, #sku := NULL) r
) s
ON t.rid = s.rid
SET sku = 'updatedSKU'
WHERE s.rn > 1;
SQL FIDDLE DEMO
Assuming rid is unique this version works without relying on the order of the data.
update skus, (
select id, min(rid) rid from skus group by id
) minimum_rid
set skus.sku = 'updated'
, skus.name = 'updated'
where skus.id = minimum_rid.id
and skus.rid > minimum_rid.rid ;