Dəyərli dostlar,
Bu yaxınlarda kifayət qədər maraqlı bir SQL məsələsini müxtəlif şəbəkələrdə elan etdim. Geri dönüşlərdən o qənaətə gəldim ki, həllini izah etməyə ehtiyac var.
Beləliklə,
Məsələnin şərtini qeyd edək:
a ve b ədədlərindən ibarət verilmiş uzunluqda bütün kombinasiyaları SQL ilə çıxarmaq lazımdır.
Məsələn,
I) uzunluq 2 olaraq verilərsə, nəticə aşağıdakı şəkildə olmalıdır:
aa
ab
ba
bb
II) uzunluq 3 olaraq verilərsə, nəticə aşağıdakı şəkildə olmalıdır:
aaa
aab
aba
abb
baa
bab
bba
bbb
Hər bir məsələnin həllində olduğu kimi, bu məsələnin də həllində ilkin olaraq, bir qanunauyğunluq tapmağa çalışaq. Beləki, nəticələrin nümunəsinə nəzər yetirsək, a hərfini 0 və b hərfini 1 kimi təsəvvür etsək, hər bir sətir həmin sətrin sıra nömrəsindən bir vahid az ədədin 2-lik say sistemində ifadə olunmuş formasıdır. Ümumi sətrlərin sayı isə 2^n qaydası ilə təyin olunacaq.
Yəni
aa >> 00
ab >> 01
ba >> 10
bb >> 11
Bu yanaşma ilə məsələni 3 hissəyə parçalayaq:
1) Ardıcıl N (N=2^n) sətrin alınması;
2) Hər sətrdəki (10-luq say sistemində olan) ədədin (sıra nömrəsi -1) 2-lik say sisteminə çevrilməsi;
3) Alınmış nəticədə 0-in ‘a’, 1-in ‘b’ simvoluna çevrilməsi.
N uzunluğunu ilkin olaraq 3-də bərabər hesab edək və ardıcıl olaraq yuxarıdakı mərhələləri SQL ilə yazaq:
1) Ardıcıl 8 (N=2^3) sətrin alınması:
Hər sətirdə həmin sətrin sıra nömrəsi -1 olan ədədi çıxarıraq.
select level-1 as base_10
from dual
connect by level<=power(2,3);
2) Hər sətrdə olan ədədin 2-lik saysisteminə çevrilməsi:
Bu mərhələ həlledici mərhələdir. Bir ədədi 10-luq say sistemindən 2-lik say sisteminə çevirmək üçün, heç bir standart SQL funksiyası istifadə etmədən, hətta məktəb proqramından bildiyimizin qaydanı tətbiq edəcəyəm. Ümumi qayda 10-luq ədədi 2-yə bölməklə, sonda alınan qismət və geriyə doğru qalıqları yanaşı yazılmasıdır.
Həmin məntiqi SQL-ə çevirək:
with seq as (select level-1 as base_10 from dual connect by level<=power(2,3)),
len as (select level as pos from dual connect by level<=3),
tab as (select base_10, mod(trunc( base_10/( power( 2,(pos-1) ) )) , 2) base_2, pos from len, seq)
select base_10, reverse(listagg(base_2, ”) within group (order by pos)) as “Result”
from tab
group by base_10
order by 1;
3) Alınmış nəticədə 0-in ‘a’, 1-in ‘b’ simvoluna çevrilməsi:
with seq as (select level-1 as base_10 from dual connect by level<=power(2,3)),
len as (select level as pos from dual connect by level<=3),
tab as (select base_10, mod(trunc( base_10/( power( 2,(pos-1) ) )) , 2) base_2, pos from len, seq)
select base_10, translate(reverse(listagg(base_2, ”) within group (order by pos)), ’01’ , ‘ab’ ) as “Result”
from tab
group by base_10
order by 1;
Beləliklə son SQL-i dinamikləşdirmək üçün, qəbul etdiyimiz N=3 ədədinin əvəzinə Substitution Variable (&N) istifadə edə bilərik:
WITH seq AS (
SELECT level – 1 AS base_10
FROM dual
CONNECT BY level <= power(2, &n)
),
len AS (
SELECT level AS pos
FROM dual
CONNECT BY level <= &n
),
tab AS (
SELECT base_10,
mod(trunc(base_10 /(power(2,(pos – 1)))), 2) base_2,
pos
FROM len, seq
)
SELECT
base_10,
translate(reverse(
LISTAGG(base_2, ”) WITHIN GROUP(ORDER BY pos)
), ’01’, ‘ab’) AS “Result”
FROM tab
GROUP BY base_10
ORDER BY 1;
Bundan əlavə digər təklif olunan variantları aşağıda müəllifləri ilə təqdim edirəm:
Arifə Məmmədzadə (Tələbəm, Junior Database Developer) :
select t,lpad(
(SELECT LISTAGG(SIGN(BITAND(t, POWER(2, LEVEL – 1))), ”) WITHIN GROUP(ORDER BY LEVEL DESC) bin FROM dual
CONNECT BY POWER(2, LEVEL – 1) <= t),
&d, 0) as combination
from (SELECT LEVEL – 1 as t FROM DUAL
CONNECT BY LEVEL <=(select power(digit, len)
from (select 2 as digit, &d as len from dual)));
Mahir Eynullayev (Ekspert):
select replace(REPLACE((lpad((SELECT LISTAGG(SIGN(BITAND(mylevel, POWER(2,LEVEL-1))),”)
WITHIN GROUP(ORDER BY LEVEL DESC) bin
FROM dual
CONNECT BY POWER(2, LEVEL-1)<=mylevel),4, ‘0’)), ‘0’, ‘a’),’1′,’b’)
from (select level-1 as mylevel from dual connect by level<=power(2,4));
Cavad Paşayev ( https://t.me/oraclesql telegram qrupumuzdan) :
select * from
(with combinations(c) as
(
select chr( ascii(‘0’) + level -1)
from dual connect by level <= 2
)
select replace (sys_connect_by_path(c, ‘ ‘), ‘ ‘, ”) as result
from combinations connect by level <= 8 — Uzunluq burda təyin olunur
order by level, result)
where length(result) = 8; — Uzunluq burda təyin olunur
Ruslan Cəlilov (Peşəkar) :
WITH TMP1 AS
(
SELECT LEVEL-1 R
FROM DUAL
CONNECT BY LEVEL <= POWER(2, :PARAM)
)
, TMP2 AS
(
SELECT LPAD(
(
SELECT LISTAGG(SIGN(BITAND(R, POWER(2,LEVEL-1))),”)
WITHIN GROUP(ORDER BY LEVEL DESC) bin
FROM dual
CONNECT BY POWER(2, LEVEL-1)<=R
), :PARAM, ‘0’) AS C
FROM TMP1
)
SELECT REPLACE(REPLACE(C, ‘0’, ‘a’), ‘1’, ‘b’) AS RES
FROM TMP2;