Custom column to represent order - mysql

I am using MySQL to return columns from a data table. What I want to do is use Order By to order the results by a date fields in ascending order and then also return a custom column along with the other desired columns where the custom column represents the index in relation to the Order By results. Right, I have the following query which just returns the desired columns and orders the results:
SELECT
`alert_id`,
`message`,
`expiration`
FROM
`alert`
WHERE
`is_active` = TRUE
ORDER BY
`expiration`
But what I'm having difficulty with is how to also return the custom column that represents the order. So for example, I would like the following (sample data) rows returned:
Pior to Order and Custom Column After the Order and Custom Column
+----------+---------+------------+ +----------+---------+------------+----------+
| alert_id | message | expiration | | alert_id | message | expiration | order_by |
+----------+---------+------------+ +----------+---------+------------+----------+
| 1 | alert1 | 2017-11-20 | | 5 | alert5 | 2017-11-16 | 1 |
| 5 | alert5 | 2017-11-16 | | 6 | alert6 | 2017-11-17 | 2 |
| 6 | alert6 | 2017-11-17 | | 1 | alert1 | 2017-11-20 | 3 |
+----------+---------+------------+ +----------+---------+------------+----------+

With AdrianE's assistance in mentioning the ROW_NUMBER function, even though I am using MySQL and that function is not available, I was able to emulate the function by using the following:
SET #order = 0;
SELECT
`alert_id`,
`message`,
DATE_FORMAT(`expiration`, '%M %D, %Y') AS formatted_date,
(#order := #order + 1) AS order_by
FROM
`alert`
WHERE
`is_active` = TRUE
ORDER BY
`expiration`;

Related

Sort Table that primary key start with letter and get last record

this my table
+---------+-----------+
| Item_No | Item_name |
+---------+-----------+
| IL1 | abc_1 |
| IL2 | abc_2 |
| IL3 | abc_3 |
| IL4 | abc_4 |
| IL5 | abc_5 |
| IL6 | abc_6 |
| IL7 | abc_7 |
| IL8 | abc_8 |
| IL9 | abc_9 |
| IL10 | abc_10 |
| IL11 | abc_11 |
+---------+-----------+
I want to Sort my Table by primary key I try this SQL
SELECT *
FROM `item_master`
WHERE Item_No LIKE 'IL%'
ORDER by I_code DESC LIMIT 1
but I gives me IL9 as last one
Your could, for example, extract number from "Item_No"(I_code?) and convert it to int:
SELECT *
FROM item_master
WHERE Item_No LIKE 'IL%'
ORDER by cast(substring(Item_No, 3) as UNSIGNED) DESC LIMIT 1
The issue that you are facing here is a wrong ordering by VARCHAR I assume, which is a string and it gets ordered lexically, here is a way to fix it:
SELECT *
FROM item_master
ORDER by right(concat('0000', Item_No), 4) DESC LIMIT 1
Notice the 0000 (4 zeros) and right() function second argument 4 is the character length for the ordering field
Another way to solve it to use LPAD
SELECT *
FROM item_master
ORDER by lpad(Item_No, 100, '0') DESC LIMIT 1
here is a working sqlfiddle to check

MySQL self join return all rows

Per the example data below, I need a query that returns every row, where if the 'contingent_on' field is NULL, it is returned as NULL, but if it is not NULL it is returned with the 'ticket_name' corresponding to the 'primary_key' value.
I tried self join queries but could only get them to return the not NULL rows.
example table data:
primary_key | ticket_name | contingent_on
1 | site preparation | NULL
2 | tender process | NULL
3 | construction | 1
All rows should be returned, where the in the 'construction' row return, 'site preparation' is input in place of '1' in the 'contingent_on' field.
You need a self left join:
select
t.primary_key,
t.ticket_name,
tt.ticket_name ticket_name2
from tablename t left join tablename tt
on tt.primary_key = t.contingent_on
order by t.primary_key
See the demo.
Results:
| primary_key | ticket_name | ticket_name2 |
| ----------- | ---------------- | ---------------- |
| 1 | site preparation | null |
| 2 | tender process | null |
| 3 | construction | site preparation |
It looks simple query:
select
primary_key,
ticket_name,
case when contingent_on is not null then ticket_name else contingent_on end as contingent_on
from <<your_table>>
order by primary_key

Select value from table sorted by a certain order from another table

I want to select value from table sorted by a certain order.
I have a table called test that looks like this:
| date | code | value |
+----------+-----------+----------+
| 20050104 | 000005.SZ | -6359.19 |
| 20050104 | 600601.SH | -7876.34 |
| 20050104 | 600602.SH | -25693.3 |
| 20050104 | 600651.SH | NULL |
| 20050104 | 600652.SH | -15309.9 |
...
| 20050105 | 000005.SZ | -4276.28 |
| 20050105 | 600601.SH | -3214.56 |
...
| 20170405 | 000005.SZ | 23978.13 |
| 20170405 | 600601.SH | 32212.54 |
Right now I want to select only one date, say date = 20050104, and then sort the data by a certain order (the order that each stock was listed in the stock market).
I have another table called stock_code which stores the correct order:
+---------+-----------+
| code_id | code |
+---------+-----------+
| 1 | 000002.SZ |
| 2 | 000004.SZ |
| 3 | 600656.SH |
| 4 | 600651.SH |
| 5 | 600652.SH |
| 6 | 600653.SH |
| 7 | 600654.SH |
| 8 | 600602.SH |
| 9 | 600601.SH |
| 10 | 000005.SZ |
...
I want to sorted the selected data by stock_code(code_id), but I don't want to use join because it takes too much time. Any thoughts?
I tried to use field but it gives me an error, please tell me how to correct it or give me an even better idea.
select * from test
where date = 20050104 and code in (select code from stock_code order by code)
order by field(code, (select code from stock_code order by code));
Error Code: 1242. Subquery returns more than 1 row
You told us that you don't want to join because it takes too much time, but the following join query is probably the best option here:
SELECT t.*
FROM test t
INNER JOIN stock_code sc
ON t.code = sc.code
WHERE t.date = '20050104'
ORDER BY sc.code_id
If this really runs slowly, then you should check to make sure you have indices setup on the appropriate columns. In this case, indices on the code columns from both tables as well as an index on test.date should be very helpful.
ALTER TABLE test ADD INDEX code_idx (code)
ALTER TABLE test ADD INDEX date_idx (date)
ALTER TABLE code ADD INDEX code_idx (code)

mySql Max function ot returning exact result

I don't know why i am not getting the exact result
SELECT MAX(MID(order_id,3,20)) As Id FROM `tbl_orders` WHERE `domain_id`=2
+------------+
| id |
+------------+
| 10121452 |
+------------+
Even i tried the same function without MID function
SELECT MAX(order_id) As Id FROM `tbl_orders` WHERE `domain_id`=2
+------------+
| id |
+------------+
| Hy10121452 |
+------------+
any my database have highest order
+--------+------------+
| id | order_id |
+--------+------------+
| 1 | Hy10121452 |
| 2 | Hy10121453 |
| 3 | Hy10121454 |
| 4 | Hy10121455 |
| 5 | Hy10121456 |
| 6 | Hy10121457 |
| 7 | Hy10121458 |
| 8 | Hy10121459 |
| 9 | Hy10121460 |
+--------+------------+
i have to increment in the highest number to generate new order No.
Is i am doing something wrong?
check your database -> table-> column the data does not contain the same values like this abc1 abc2 abc3 xxx1 if you differnt series then the result always wrong
Change MAX(MID(order_id,3,20)) to MAX(MID(order_id,3,))
Syntax:from W3School
SELECT MID(column_name,start[,length]) AS some_name FROM table_name;
where
column_name Required. The field to extract characters from
start Required. Specifies the starting position (starts at 1)
length Optional. The number of characters to return. If omitted, the MID() function returns the rest of the text
Since you want the highest id then you can use order by DESC and limit
SELECT order_id As Id FROM `tbl_orders` WHERE `domain_id`=2 ORDER BY order_id DESC LIMIT 1
Problem Solved i just have to rectify Order_id column it contains the duplicate entries. duplicate entries removed and problem solved like a charm.

Converting Previous Row Subquery into a Join in MySQL

I have policy information in a policy table. Each row represents the policy status at a certain time (the time is stored in an updated_on column). Each row belongs to a policy iteration (multiple policy rows can belong to a single policy iteration). I want to look at status changes from row to row within a policy iteration.
The policy table:
CREATE TABLE `policy` (
`policy_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`policy_iteration_id` int(10) unsigned NOT NULL,
`policy_status_id` tinyint(3) unsigned NOT NULL,
`updated_on` datetime NOT NULL,
PRIMARY KEY (`policy_id`),
KEY `policy_iteration_idx` (`policy_iteration_id`),
KEY `policy_status_updated_idx` (`policy_status_id`,`updated_on`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I want to be able to pass a date range and a "from" status and a "to" status and return the policy data for the "to" row. So in pseudo code, I need to group by policy iteration, find rows that satisfy the data range and the "to" status, then look at the previous row within that policy iteration to see if it has the "from" status. If so, return the "to" row's information.
This is the query I came up with:
SELECT
pto.policy_iteration_id,
pto.policy_id,
pto.updated_on,
FROM
policy AS pto
WHERE
pto.updated_on >= $from_date AND
pto.updated_on <= $to_date AND
pto.policy_status_id = $to_status_id AND
$from_status_id =
(SELECT
pfrom.policy_status_id
FROM
policy AS pfrom
WHERE
pfrom.policy_iteration_id = pto.policy_iteration_id AND
pfrom.policy_id < pto.policy_id
ORDER BY
pfrom.policy_id DESC
LIMIT
1);
This query works but is very inefficient because of the subquery having to be executed for each row. I'd like to make it more efficient by using subquery join(s) but I can't figure out how.
Any help would be appreciated. Thanks!
UPDATE #1
To help explain what I'm trying to do, here is an example data set:
+-----------+---------------------+------------------+---------------------+
| policy_id | policy_iteration_id | policy_status_id | updated_on |
+-----------+---------------------+------------------+---------------------+
| 323705 | 27230 | 6 | 2014-08-01 10:27:11 |
| 325028 | 27230 | 2 | 2014-08-01 17:12:28 |
| 323999 | 27591 | 2 | 2014-08-01 12:07:31 |
| 324008 | 27591 | 6 | 2014-08-01 12:10:23 |
| 325909 | 27591 | 2 | 2014-08-02 14:59:12 |
| 327116 | 29083 | 6 | 2014-08-04 12:09:16 |
| 327142 | 29083 | 6 | 2014-08-04 12:19:00 |
| 328067 | 29083 | 2 | 2014-08-04 17:58:41 |
| 327740 | 29666 | 3 | 2014-08-04 16:16:55 |
| 327749 | 29666 | 3 | 2014-08-04 16:19:01 |
+-----------+---------------------+------------------+---------------------+
Now if I run the query where from_date = '2014-08-02 00:00:00', to_date = '2014-08-05 00:00:00', from_status = 6 and to_status = 2, the result should be:
+-----------+---------------------+------------------+---------------------+
| policy_id | policy_iteration_id | policy_status_id | updated_on |
+-----------+---------------------+------------------+---------------------+
| 325909 | 27591 | 2 | 2014-08-02 14:59:12 |
| 328067 | 29083 | 2 | 2014-08-04 17:58:41 |
+-----------+---------------------+------------------+---------------------+
Those two rows have a row with the selected "to_status" of 2 within the stated time period and have their previous row with the "from_status" of 6.
I don't believe joining a MAX policy id with a GROUP BY of policy_iteration_id will do the job since that would return the rows that are most recent, not the row that is previous to the row with the "to_status".
Any further help would be appreciated. Thanks!
You can use use max from.policy_id where from.policy_id < to.policy_id to help get the previous row as a set.
select
p.policy_iteration_id,
p.policy_id,
p.updated_on
from
policy f
inner join (
select
p.policy_iteration_id,
p.policy_id,
p.updated_on,
max(f.policy_id) as prev_policy_id
from
policy p
inner join
policy f
on f.policy_iteration_id = p.policy_iteration_id and
f.policy_id < p.policy_id
where
p.updated_on >= $from_date and
p.updated_on <= $to_date and
p.policy_status_id = $to_status_id
group by
p.policy_iteration_id,
p.policy_id,
p.updated_on
) p
on p.prev_policy_id = f.policy_id
where
f.policy_status_id = $from_status_id
In a database with window functions there are simpler ways of achieving this.
Example SQLFiddle