I need to sort the ID field, but the id field is dynamic, I need to judge before sorting, if it is a pure number, then I convert it to a numeric type and then sort. But I have some problems in order by case when cast(),can somebody help me?
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for BASIS_EXP_ORG
-- ----------------------------
DROP TABLE IF EXISTS `BASIS_EXP_ORG`;
CREATE TABLE `BASIS_EXP_ORG` (
`NAME` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'name',
`ORG_ID` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'org',
PRIMARY KEY (`ORG_ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of BASIS_EXP_ORG
-- ----------------------------
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_2', '101');
INSERT INTO `BASIS_EXP_ORG` VALUES ('INV_2', '141');
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_1', '85');
SET FOREIGN_KEY_CHECKS = 1;
----------------------------------------------------------------
select distinct ORG_ID as id,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by
case when ORG_ID REGEXP '(^[0-9])'
then ORG_ID +0
ELSE ORG_ID END
asc
Is this what you want?
I think you just need to place (ORG_ID + 0) at the order by phase to cast it to numeric type.
Please try this.
select distinct ORG_ID,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by (ORG_ID + 0) DESC
If you're using MySQL version 8+ and MariaDB 10+, you can use REGEXP_REPLACE to remove strings then CAST it:
SELECT DISTINCT ORG_ID AS id,CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED),
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED) ASC;
Check demo here: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/0
I added a few row data in the fiddle and remove the and ORG_ID in (101,141,85) in WHERE condition for testing purpose.
EDIT:
This query below should be able to get it working on older MySQL:
SELECT DISTINCT ORG_ID AS id,SUBSTRING(ORG_ID,
LEAST(
IF(LOCATE(1,org_id)=0,99,LOCATE(1,org_id)),
IF(LOCATE(2,org_id)=0,99,LOCATE(2,org_id)),
IF(LOCATE(3,org_id)=0,99,LOCATE(3,org_id)),
IF(LOCATE(4,org_id)=0,99,LOCATE(4,org_id)),
IF(LOCATE(5,org_id)=0,99,LOCATE(5,org_id)),
IF(LOCATE(6,org_id)=0,99,LOCATE(6,org_id)),
IF(LOCATE(7,org_id)=0,99,LOCATE(7,org_id)),
IF(LOCATE(8,org_id)=0,99,LOCATE(8,org_id)),
IF(LOCATE(9,org_id)=0,99,LOCATE(9,org_id))),99)+0 AS num,
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY num ASC;
Demo on MySQL 5.7: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/3
As you can see, I'm using a series of functions to remove the strings from the original data. First I use LOCATE to find numbers range from 1-9 and their location. The following query and result can help to clarify more:
SELECT *,
LOCATE(1,org_id),
LOCATE(2,org_id),
LOCATE(3,org_id),
LOCATE(4,org_id),
LOCATE(5,org_id),
LOCATE(6,org_id),
LOCATE(7,org_id),
LOCATE(8,org_id),
LOCATE(9,org_id) FROM BASIS_EXP_ORG;
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| NAME | ORG_ID | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE |
| | | (1,org_id) | (2,org_id) | (3,org_id) | (4,org_id) | (5,org_id) | (6,org_id) | (7,org_id) | (8,org_id) | (9,org_id) |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| OU_1 | 00000001 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | 101 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| INV_2 | 141 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_3 | 81 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| OU_1 | 85 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 1 | 0 |
| INV_2 | a101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | b40 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | c0001 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | c101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
The logic behind this is to know where is the location of the number stated in LOCATE (if any). Then if it returns 0 (meaning the number doesn't exists), give it 99 so when the LEAST happen, it won't see zeros. The main reason of using LEAST however is to get the first number found instead of the smallest number found. That being said, refer to the example above and look for the data with ORG_ID=81. (LOCATE(1,org_id) found number 1 in location 2 while (LOCATE(8,org_id) found the number 8 in location 1. If we took the smallest number to judge, then we will get number 1 instead of 81 in the SUBSTRING function (this took me a while to figure out ;P). Then we use them all in the SUBSTRING and we add +0 at the last value retrieved.
tl;dr > if we convert this into plain query, we will get basically something like this:
SELECT DISTINCT ORG_ID AS id, SUBSTRING(ORG_ID,**8**,99)+0 as num
FROM BASIS_EXP_ORG
WHERE 1 = 1
AND ORG_ID='00000001'
ORDER BY num ASC;
To obtain the **8** is where all the process happen.
I'm trying to remove certain letters from part numbers but I'm having difficulties trying to get it working correctly.
This is where I'm at right now. It's non functional.
SELECT REPLACE(`part`, '[0-9]L', '') FROM `table` WHERE (`part ` LIKE '%[0-9]L')
Essentially say I have these five items:
D39J02GEN
20F934L
2984CPL
29048L20GEN
1120934L
I only want the ones in bold to be detected. So where they end in L, only if they have a number before the L.
Edit: this one gets close:
SELECT * FROM `table ` WHERE `part` REGEXP '^[0-9].*L';
but still shows ones where there is anything after the L. This is also no closer to removing the letter L.
If you know the value is at the end, then do:
SELECT LEFT(part, LENGTH(part) - 2)
FROM `table`
WHERE part REGEXP '[0-9]L$';
This would be much trickier if the pattern were in the middle of the string.
Something like this should also work if the match is always required at the end of the text.
Query
SELECT
*
FROM
t
WHERE
SUBSTRING(REVERSE(t.text_string), 1, 1) = 'L'
AND
SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0
Result
| text_string |
| ----------- |
| 20F934L |
| 1120934L |
see demo
Note
SUBSTRING(REVERSE(t.text_string), 2) >> 0 basically means CAST(SUBSTRING(REVERSE(t.text_string), 2) AS UNSIGNED) here
Why this works?
I use MySQL's loose autocasting feature which can convert 439F02 in a INT 439 but it can't convert PC4892 into a INT it would be converted into 0
See the below resultset based on the query
Query
SELECT
*
, SUBSTRING(REVERSE(t.text_string), 1, 1)
, SUBSTRING(REVERSE(t.text_string), 2)
, SUBSTRING(REVERSE(t.text_string), 2) >> 0
, SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0
FROM
t
Result
| text_string | SUBSTRING(REVERSE(t.text_string), 1, 1) | SUBSTRING(REVERSE(t.text_string), 2) | SUBSTRING(REVERSE(t.text_string), 2) >> 0 | SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0 |
| ----------- | --------------------------------------- | ------------------------------------ | ----------------------------------------- | ---------------------------------------------- |
| D39J02GEN | N | EG20J93D | 0 | 0 |
| 20F934L | L | 439F02 | 439 | 1 |
| 2984CPL | L | PC4892 | 0 | 0 |
| 29048L20GEN | N | EG02L84092 | 0 | 0 |
| 1120934L | L | 4390211 | 4390211 | 1 |
Here is a demo to see the above results for yourself.
Given a table
+------------+-----------+
| Number | Count |
+------------+-----------+
| 0 | 7 |
+------------+-----------+
| 1 | 1 |
+------------+-----------+
| 2 | 3 |
+------------+-----------+
| 4 | 1 |
+------------+-----------+
Which is representing such a number sequence: 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 4
find the median number, in this case it's 0, with sql. You will need to run this query in hive (qubole)
Thoughts?
There is a fairly straightforward solution in Hive. You'll need this UDF here. Essentially, you want to un-aggregate your count data and then percentile it.
Query:
add jar /path/to/jar/brickhouse-0.7.1.jar;
create temporary function numeric_range as 'brickhouse.udf.collect.NumericRange';
select percentile(number, 0.50) median
from (
select number
from db.table
lateral view numeric_range(count) n1 as n) x
The inner query will produce
0
0
0
0
0
0
0
1
2
2
2
4
Then you can just use the percentile() function on this column
Output:
median
------
0.0
say I have a simple tree type table
id(key) | parent | order
============================
1 | 0 | 0
2 | 0 | 1
4 | 2 | 0
5 | 2 | 1
6 | 2 | 2
I want to insert a new node so that it has parent = 2 and order = 1, so it then the table data looks like:
id(key) | parent | order
============================
1 | 0 | 0
2 | 0 | 1
4 | 2 | 0
5 | 2 | 2
6 | 2 | 3
7 | 2 | 1
E.g. existing rows increment their order value.
What's the best way to ensure that existing rows increment their order (non-key field) starting at an existing arbitrary value, to make a hole for my insert statement?
If you have a new row with parent $p and order position $o you can:
UPDATE table SET order = order + 1 WHERE parent = $p AND order >= $o
and then:
INSERT INTO order (id,parent,order) VALUES($id,$p,$o)
In my application there are products and a product-variant-group which has a defined set of properties which a product of this group must declare and the combination of the properties is unique across that product-variant-group.
Example screen from amazon:
In the image the first select menu has all values obviously. The next select menu depends on the previously selected value, and so on.
Those defined group properties have a unique priority assigned to it which in the following derived table equals the property itself.
For a given property/priority and given list of of property/priority-value pairs. I want to retrieve its possible values.
The priorities of the value pairs must be smaller then the given priority.
public String[] getProductVariantGroupValues(int productVariantGroupId, int priority, Map<Integer, String> prevValues);
An example makes it much clearer:
I have an sql statement which lists all product-variant-group properties that related products have defined:
+---------+----------+-------- +
| product | priority | value |
+---------+----------+---------+
| 1 | 1 | Black |
| 1 | 2 | 38 |
| 1 | 3 | Dots |
| 2 | 1 | Black |
| 2 | 2 | 38 |
| 2 | 3 | Stripes |
| 3 | 1 | Yellow |
| 3 | 2 | 40 |
| 3 | 3 | Stripes |
+---------+----------+---------+
Other view for understanding *(priority is arbitrary just for understanding, with this view this would be trivial)*:
+---------+--------+--------+---------+
| product | value1 | value2 | value3 |
+---------+--------+--------+---------+
| 1 | Black | 38 | Dots |
| 2 | Black | 38 | Stripes |
| 3 | Yellow | 40 | Stripes |
+---------+---------------------------+
Call the above method with priority = 3 and prevValues = {(1, Black), (2, 38)} should result in following result array: {Dots, Stripes}.
If black is selected for property/priority 1 and 38 is selected for property/priority 2 the only possible following values for property/priority 3 are {Dots, Stripes}
The example is simplified and an arbitrary number of properties/priority should be supported. The query must be created dynamically to support arbitrary number of lower priority values.
Maybe I should just use the second table appraoch with a fixed set of properties which would make the unique constraint and this query very simple.
If I understand the question correctly, you have a value for priority 1 and for priority 2 and want to get all priority 3 values that match. The following query gets the products:
select product
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
To get the priority 3 values requires or a clever select statement (assuming priorities are not repeated for a product):
select product, max(case when priority = 3 then value end)
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
These queries are to give you an idea of how to construct the queries in your code. The generalization should be pretty straightforward.