'X' Pattern in SQL - sql

I am trying to generate a X pattern in SQL like below:
100001
010010
001100
010010
100001
It's a Grid Structure of 5x6 : 5 records with a value of 6 digits.
It may have dynamic grid of a given even number like 4, 8.
Any ideas will be really helpful.
I was trying something like below, Pattern:
select rpad('1',level, '1') from dual connect by level <= 5
But this would only form a right angle triangle
1
11
111
1111
11111

Using the recursiveness of a connect is a nice method.
The query below will generate an X in grid.
With a size you can choose by changing the number in the inner query.
select lpad('1',y,'0')||rpad('0',n-y*2,'0')||rpad('1',y,'0') as X
from (
select level as lvl, n, case when level<n/2 then level else n-level end as y
from (select 6 as n from dual)
connect by level < n
)
order by lvl
The subquery will generate numbers based on n.
For example, if n = 6 then the subquery will generate:
lvl n y
--- -- --
1 6 1
1 6 2
3 6 3
4 6 2
5 6 1
Then in the outer query those n and y numbers are used to calculate the amount of 0 to pad to the left, the middle and the right side.
When using 8 for n it generates the following grid:
10000001
01000010
00100100
00011000
00100100
01000010
10000001
To make it work also for the uneven numbers a few (mod)ifications are needed.
select lpad('1',y,'0')||rpad('0',n-y*2,'0')||case when mod(n,2) = 1 and lvl = trunc(n/2)+1 then rpad('0',y-1,'0') else rpad('1',y,'0') end as X
from (
select level as lvl, n, case when level<trunc(n/2)+mod(n,2) then level else n+mod(n,2)-level end as y
from (select 5 as n from dual)
connect by level < (case when mod(n,2) = 1 then n+1 else n end)
) q
order by lvl
For n = 5 that would generate:
10001
01010
00100
01010
10001

Related

How to update table with concatenation

I have table like this
create table aaa (id int not null, data varchar(50), numb int);
with data like this
begin
for i in 1..30 loop
insert into aaa
values (i, dbms_random.string('L',1),dbms_random.value(0,10));
end loop;
end;
now im making this
select a.id, a.data, a.numb,
count(*) over (partition by a.numb order by a.data) count,
b.id, b.data,b.numb
from aaa a, aaa b
where a.numb=b.numb
and a.data!=b.data
order by a.data;
and i want to update every row where those numbers are the same but with different letters, and in result i want to have new data with more than one letter (for example in data column- "a c d e"), i just want to create concatenation within. How can i make that? the point is to make something like group by for number but for that grouped column i would like to put additional value.
that is how it looks like in begining
id | data |numb
1 q 1
2 z 8
3 i 7
4 a 2
5 q 4
6 h 1
7 b 9
8 u 9
9 s 4
That i would like to get at end
id | data |numb
1 q h 1
2 z 8
3 i 7
4 a 2
5 q s 4
7 b u 9
Try this
SELECT MIN(id),
LISTAGG(data,' ') WITHIN GROUP(
ORDER BY data
) data,
numb
FROM aaa GROUP BY numb
ORDER BY 1
Demo
This selects 10 random strings 1 to 4 letters long, letters in words may repeat:
select level, dbms_random.string('l', dbms_random.value(1, 4))
from dual connect by level <= 10
This selects 1 to 10 random strings 1 to 26 letters long, letters do not repeat and are sorted:
with aaa(id, data, numb) as (
select level, dbms_random.string('L', 1),
round(dbms_random.value(0, 10))
from dual connect by level <= 30)
select numb, listagg(data) within group (order by data) list
from (select distinct data, numb from aaa)
group by numb

how to generate consecutive records with a given number?

in oracle, is there a built-in function to produce consecutive records with a given number? For example, the number is 100, so that you can generate a result-set with 100 records whose values are 1, 2, 3, 4...100, like the following:
1
2
3
4
...
100
I know store procedure can do this, and I want to know if there are other ways just using sql statements?
select level
from dual
connect by level <= 100
Here is another approach, using model clause. (Oracle 10g and higher).
SQL> select x
2 from dual
3 model
4 dimension by (0 as z)
5 measures (0 as x)
6 rules iterate(101) (
7 x[iteration_number] = iteration_number
8 )
9 ;
X
----------
0
1
2
3
4
5
6
7
8
9
10
11
...
100
Please try using CTE:
WITH numbers(n) AS
(
SELECT 1 FROM dual
UNION ALL
SELECT n + 1 FROM numbers WHERE n < 100
)
SELECT * FROM numbers;
It's traditional to use a hierarchical query:
select level
from dual
connect by level <= 100

Why does CONNECT BY LEVEL on a table return extra rows?

Using CONNECT BY LEVEL seems to return too many rows when performed on a table. What is the logic behind what's happening?
Assuming the following table:
create table a ( id number );
insert into a values (1);
insert into a values (2);
insert into a values (3);
This query returns 12 rows (SQL Fiddle).
select id, level as lvl
from a
connect by level <= 2
order by id, level
One row for each in table A with the value of column LVL being 1 and three for each in table A where the column LVL is 2, i.e.:
ID | LVL
---+-----
1 | 1
1 | 2
1 | 2
1 | 2
2 | 1
2 | 2
2 | 2
2 | 2
3 | 1
3 | 2
3 | 2
3 | 2
It is equivalent to this query, which returns the same results.
select id, level as lvl
from dual
cross join a
connect by level <= 2
order by id, level
I don't understand why these queries return 12 rows or why there are three rows where LVL is 2 and only one where LVL is 1 for each value of the ID column.
Increasing the number of levels that are "connected" to 3 returns 13 rows for each value of ID. 1 where LVL is 1, 3 where LVL is 2 and 9 where LVL is 3. This seems to suggest that the rows returned are the number of rows in table A to the power of the value of LVL minus 1.
I would have though that these queries would be the same as the following, which returns
6 rows
select id, lvl
from ( select level as lvl
from dual
connect by level <= 2
)
cross join a
order by id, lvl
The documentation isn't particularly clear, to me, in explaining what should occur. What's happening with these powers and why aren't the first two queries the same as the third?
When connect by is used without start with clause and prior operator, there is no restriction on joining children row to a parent row. And what Oracle does in this situation, it returns all possible hierarchy permutations by connecting a row to every row of level higher.
SQL> select b
2 , level as lvl
3 , sys_connect_by_path(b, '->') as ph
4 from a
5 connect by level <= 2
6 ;
B LVL PH
---------- ----------
1 1 ->1
1 2 ->1->1
2 2 ->1->2
3 2 ->1->3
2 1 ->2
1 2 ->2->1
2 2 ->2->2
3 2 ->2->3
3 1 ->3
1 2 ->3->1
2 2 ->3->2
3 2 ->3->3
12 rows selected
In the first query, you connect by just the level.
So if level <= 1, you get each of the records 1 time. If level <= 2, then you get each level 1 time (for level 1) + N times (where N is the number of records in the table). It is like you are cross joining, because you're just picking all records from the table until the level is reached, without having other conditions to limit the result. For level <= 3, this is done again for each of those results.
So for 3 records:
Lvl 1: 3 record (all having level 1)
Lvl 2: 3 records having level 1 + 3*3 records having level 2 = 12
Lvl 3: 3 + 3*3 + 3*3*3 = 39 (indeed, 13 records each).
Lvl 4: starting to see a pattern? :)
It's not really a cross join. A cross join would only return those records that have level 2 in this query result, while with this connect by, you get the records having level 1 as well as the records having level 2, thus resulting in 3 + 3*3 instead of just 3*3 record.
you're comparing apples to oranges when comparing the final query to the others as the LEVEL is isolated in that to the 1-row dual table.
lets consider this query:
select id, level as lvl
from a
connect by level <= 2
order by id, level
what that is saying is, start with the table set (select * From a). then, for each row returned connect this row to the prior row. as you have not defined a join in the connect by, this is in effect a Cartesian join, so when you have 3 rows of (1,2,3) 1 joins to 2, 1->3, 2->1, 2->3, 3->1 and 3->2 and they also join to themselves 1->1,2->2 and 3->3. these joins are level=2. so we have 9 joins there, which is why you get 12 rows (3 original "level 1" rows plus the Cartesian set).
so the number of rows output = rowcount + (rowcount^2)
in the last query you are isolating level to this
select level as lvl
from dual
connect by level <= 2
which of course returns 2 rows. this is then cartesianed to the original 3 rows, giving 6 rows as output.
You can use technique below to overcome this issue:
select id, level as lvl
from a
left outer join (select level l from dual connect by level <= 2) lev on 1 = 1
order by id

SQL conditional select for value in the same table group

We have a table like this:
id mid mult tr result
----------------------------
1 1 1,35 0 1
2 1 5,85 0 2
3 1 4 1 X
50 2 1,3 1 1
51 2 7 0 2
52 2 4 0 X
99 3 2,45 0 1
100 3 2,2 0 2
101 3 3,3 1 X
105 4 2,3 0 1
106 4 2,4 0 2
107 4 3,2 1 X
111 5 3 1 1
112 5 1,9 0 2
113 5 3,25 0 X
What we need is a query that will bring us a table which will count how many times before, for a specific mid(match), have the same mults(multipliers) for result = 1 and result = x have occurred and group them so that we can count them. Something like
select mult(where result = 1), mult(where result = x), count(1)
The result will be like this
mult_1 mult_x count
------------------------------
1,35 4 33
1,3 4 112
The above states that we have seen 33 matches where the mult for result = 1 was 1,35 AND mult for result = x was 4. Also, we found 112 matches where multi for result = 1 was 1,3 AND for result = x mult was 4 (results are not dependant on the first table).
I find it rather complex myself, but hopefully I made sense. I use SQL Server 2008, so any method is more than welcome.
Here is my (final) solution in action: http://www.sqlfiddle.com/#!3/3a516/7
There are a number of assumptions I'm making here.
I'm assuming that every mid value is going to have at most 1 result value of '1' and 1 result of '2'.
I'm assuming that if you want to specify a mid and have the query run off of that.
This assumption turned out to be wrong.
I'm assuming that you want to include the data for the mid you specify.
This assumption turned out to be wrong, it was every match.
I'm assuming that you want to include every mid (or match) before the mid you specify.
This assumption turned out to be wrong, it was every match.
I'm assuming that for any mult_1 and mult_x combination you find in this way, you want the count of how many times that combination occurs, even if it occurs after the match(mid) that you specified.
This assumption turned out to be wrong, it was just for every match.
If all of these assumptions sound right, then this might create the result you're looking for:
DECLARE #Mid INT = 2
;WITH MatchResults AS
(
SELECT
Mid
, [1] AS MultWithResult1
, [X] AS MultWithResultX
FROM
(
SELECT
Mid
, mult
, result
FROM Matches
WHERE result IN ('1', 'X')
) Base
PIVOT
(
MAX(mult)
FOR result
IN
(
[1]
, [X]
)
) Pivoted
)
SELECT
mult.MultWithResult1 AS mult_1
, mult.MultWithResultX AS mult_x
, COUNT(*) AS [count]
FROM MatchResults mult
GROUP BY mult.MultWithResult1
, mult.MultWithResultX
EDIT: I have edited it based on the response to my answer to what I think he means.
Use this query:
select mult_1, mult_x, count() as count
from Matches M
inner join (select distinct M1.mult as mult_1, MX.mult as mult_x from
matches as M1, matches as MX
where M1.result=1 and MX.result=x) M1x
on (M.mult=M1x.mult_1 and M.result=1) or (M.mult=M1x.mult_x and result=x)
group by mult_1, mult_x
EDIT:
I'm supposing you wnat to get the count of all possible combinations of multipliers of matches with result=1 and matches with result = x.
If this is the case, M1x gives all this possible combinations. And you join all the possible matchea with have any of those combinations, and count them, grouping by the possible set of combinations defined by M1x.

Using random value as join condition

I am generating some test-data and use dbms_random. I encountered some strange behavior when using dbms_random in the condition of the JOIN, that I can not explain:
------------------------# test-data (ids 1 .. 3)
With x As (
Select Rownum id From dual
Connect By Rownum <= 3
)
------------------------# end of test-data
Select x.id,
x2.id id2
From x
Join x x2 On ( x2.id = Floor(dbms_random.value(1, 4)) )
Floor(dbms_random.value(1, 4) ) returns a random number out of (1,2,3), so I would have expected all rows of x to be joined with a random row of x2, or maybe always the same random row of x2 in case the random number is evaluated only once.
When trying several times, I get results like that, though:
(1) ID ID2 (2) ID ID2 (3)
---- ---- ---- ---- no rows selected.
1 2 1 3
1 3 2 3
2 2 3 3
2 3
3 2
3 3
What am I missing?
EDIT:
SELECT ROWNUM, FLOOR(dbms_random.VALUE (1, 4))
FROM dual CONNECT BY ROWNUM <= 3
would get the result in this case, but why does the original query behave like that?
To generate three rows with one predictable value and one random value, try this:
SQL> with x as (
2 select rownum id from dual
3 connect by rownum <= 3
4 )
5 , y as (
6 select floor(dbms_random.value(1, 4)) floor_val
7 from dual
8 )
9 select x.id,
10 y.floor_val
11 from x
12 cross join y
13 /
ID FLOOR_VAL
---------- ----------
1 2
2 3
3 2
SQL
edit
Why did your original query return an inconsistent set of rows?
Well, without the random bit in the ON clause your query was basically a CROSS JOIN of X against X - it would have returned nine rows (at least it would have if the syntax had allowed it). Each of those nine rows executes a call to DBMS_RANDOM.VALUE(). Only when the random value matches the current value of X2.ID is the row included in the result set. Consequently the query can return 0-9 rows, randomly.
Your solution is obviously simpler - I didn't refactor enough :)