I sort my data with select pk_customer_no from customer order by pk_customer_no
The code with '-', didn't group together and sort by letter, It seems sql just ignore it and sort by the third letter.
How can I sort by the '-'?
The '-' character is ignored in sorting.
You can use order by replace '-' with '0' (zero), if you want to put the words with '-' in front.
select t.pk_customer_no as rep from (
values ('YH'), ('YHC'), ('Z-CH'), ('Z-CHE'), ('ZCM'), ('Z-CP'), ('Z1'), ('ZHT'), ('ZLA'), ('Z-JP'), ('ZLENO')
) as t (pk_customer_no)
order by replace(t.pk_customer_no, '-', '0')
You can use order by replace '-' with 'Z' if you want to put the words with '-' at the end.
select t.pk_customer_no as rep from (
values ('YH'), ('YHC'), ('Z-CH'), ('Z-CHE'), ('ZCM'), ('Z-CP'), ('Z1'), ('ZHT'), ('ZLA'), ('Z-JP'), ('ZLENO')
) as t (pk_customer_no)
order by replace(t.pk_customer_no, '-', 'Z')
Related
Oracle Database 19c Enterprise Edition
I have a table with various codes as listed below. Code is prefixed with an alphabet and then followed by a number. Some are in sequence, and some are individual or random independent numbers.
A1,A2,A3,A4,A5,A8,A9,A10,A11,A12,B3,B5,B7,B8,B9,B110,B111,B112,C1,C2,C3,C4,C5,C6,C7,C8
I want to display them in ranges as shown below. Here is the link to the schema and data: SQL Fiddle
Expected Output:
A1-A5
A8-A12
B3
B5
B7-B9
B110-B112
C1-C8
I tried solutions like http://lalitkumarb.wordpress.com/2015/07/22/find-range-of-consecutive-values-in-a-sequence-of-numbers-or-dates/ but doesn't work for me as I have the letter prefixed to the number.
From Oracle 12, you can split the string into prefix and suffix and then use MATCH_RECOGNIZE to efficiently perform row-by-row pattern matching:
SELECT prefix || first_suffix || '-' || prefix || last_suffix AS range
FROM (
SELECT TRANSLATE(ref_code, 'A0123456789', 'A') AS prefix,
TO_NUMBER(TRANSLATE(ref_code, '0ABCDEFGHIJKLMONPQRSTUVWXYZ', '0')) AS suffix
FROM xx_ref_codes
)
MATCH_RECOGNIZE(
PARTITION BY prefix
ORDER BY suffix
MEASURES
FIRST(suffix) AS first_suffix,
LAST(suffix) AS last_suffix
PATTERN (consecutive* final_row)
DEFINE consecutive AS suffix + 1 = NEXT(suffix)
);
Or, if you want to use analytic functions and then aggregate then:
SELECT prefix || MIN(suffix) || '-' || prefix || MAX(suffix) AS range
FROM (
SELECT prefix,
suffix,
suffix - ROW_NUMBER() OVER (PARTITION BY prefix ORDER BY suffix) AS grp
FROM (
SELECT TRANSLATE(ref_code, 'A0123456789', 'A') AS prefix,
TO_NUMBER(TRANSLATE(ref_code, '0ABCDEFGHIJKLMONPQRSTUVWXYZ', '0')) AS suffix
FROM xx_ref_codes
)
)
GROUP BY prefix, grp
Which, for your sample data, both output:
RANGE
A1-A5
A8-A12
B3-B3
B5-B5
B7-B9
B110-B112
C1-C8
fiddle
Could also be solved with standard SQL:
select header || min(num) || case when min(num) <> max(num) then '-' || header || max(num) end as result
from (
select substr(ref_code,1,1) as header, to_number(substr(ref_code,2)) as num,
to_number(substr(ref_code,2)) - row_number() over(partition by substr(ref_code,1,1) order by to_number(substr(ref_code,2))) as grp, ref_code
from xx_ref_codes
)
group by header, grp
;
A1-A5
A8-A12
B3
B5
B7-B9
B110-B112
C1-C8
I want to search for the occurrence of words in a database row. I use SQLite as a database. The search needs to be case-insensitive.
Let's say row x is Hello. Today is Monday and I want to search for Hello Monday Bye and still return the row x because the Hello and Monday exist in the row.
I used Like operator %Hello%Tuesday%Bye% but this defiantly doesn't work and I can't use Glob because it's not case-insensitive. Any suggestion, how can I do the search?
Also, the order shouldn't matter and Monday Hello should return a row as well
You can extend SQLite with regular expressions and then use:
where col regexp replace($searchfor, ' ', '|')
This will return any time there is a match with any of the values.
First create a recursive CTE to split the string 'Hello Monday Bye' which contains the words you search for.
Then join it to the table:
with cte as (
select null word, 'Hello Monday Bye' || ' ' rest
union all
select substr(rest, 1, instr(rest, ' ') - 1),
substr(rest, instr(rest, ' ') + 1)
from cte
where length(rest) > 0
)
select distinct t.*
from tablename t inner join cte c
on t.col like '%' || c.word || '%'
See the demo.
Let's think we have a table of meaningful words (like a dictionary), and we have a "set of letters" as an input, and we want to find all the meaningful words found in our source table that are made with the given set of letters, considering that not all the given letters need to be used in the result, but all the letters of the result need to be part of given set of letters.
Dictionary
----------
in
ink
inn
inbox
Input: unmin
Result
------
in
inn
You can break the string into its letters using a recursive CTE and then make sure that the dictionary only has those letters:
with cte as (
select left(#input, 1) as letter, stuff(#input, 1, 1, '') as rest
union all
select left(rest, 1), stuff(rest, 1, 1, '')
from cte
where rest <> ''
)
select d.word
from dictionary d join
cte
on d.word like '%' + cte.letter + '%'
group by d.word
having count(*) = len(d.word)
Here is a db<>fiddle.
I want to display page number in ascending order. But, since the field PAGE is of String datatype, normal 'ORDER BY' considers 10 < 2. I have to make the field PAGE as String because there can be inputs like '3-4'. Can anyone please suggest a way out. I've attached screenshot for reference.
Kindly help.Screenshot
select id
,F_NL
,page
,title
from newsletter_content
where F_NL = '29'
order by page asc;
select page from p
order by to_number(nvl(substr(page, 1, instr(page, '-')-1), page))
rextester demo
You can check for the presence of a - character and extract the preceding number:
ORDER BY CASE
WHEN INSTR( page, '-' ) > 0
THEN TO_NUMBER( SUBSTR( page, 1, INSTR( page, '-' ) - 1 ) )
ELSE TO_NUMBER( page )
END;
I have a situation where I want to remove the duplicated record from the result by using sql query in oracle 10g. I am using regular expression to remove the alphabets from the result
Original value = 1A,1B,2C,2F,4A,4z,11A,11B
Current Sql query
select REGEXP_REPLACE( tablex.column, '[A-Za-z]' , '' )
from db1
gives me the following output
1,1,2,3,4,4,11,11
how can i remove duplicate from the output to just show unique values
i.e.
1,2,3,4,11
Assuming that your table contains strings with values separated with commas.
You can try something like this:
Here is a sqlfiddle demo
select rtrim(xmltype('<r><n>' ||
replace(REGEXP_REPLACE( col, '[A-Za-z]' , '' ), ',', ',</n><n>')||',</n></r>'
).extract('//n[not(preceding::n = .)]/text()').getstringval(), ',')
from tablex;
What it does is after using your regexp_replace it makes a xmltype from it and then uses XPATH to get the desired output.
If you also want to sort the values (and still use the xml approach) then you need XSL
select rtrim(xmltype('<r><n>' ||
replace(REGEXP_REPLACE( col, '[A-Za-z]' , '' ), ',', '</n><n>')||'</n></r>'
).extract('//n[not(preceding::n = .)]')
.transform(xmltype('<?xml version="1.0" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><xsl:for-each select="//n[not(preceding::n = .)]"><xsl:sort select="." data-type="number"/><xsl:value-of select="."/>,</xsl:for-each></xsl:template></xsl:stylesheet>'))
.getstringval(), ',')
from tablex;
But you can also try different approaches, such as splitting the tokens to rows and then recollecting them
select rtrim(xmlagg(xmlelement(e, n || ',') order by to_number(n))
.extract('//text()'), ',')
from(
SELECT distinct rn, trim(regexp_substr(col, '[^,]+', 1, level)) n
FROM (select row_number() over (order by col) rn ,
REGEXP_REPLACE( col, '[A-Za-z]' , '' ) col
from tablex) t
CONNECT BY instr(col, ',', 1, level - 1) > 0
)
group by rn;