Oracle SQL: Combine list of char with values - sql

In Oracle SQL, I want to create a view.
In Column 1, it should have a distinct list of chars.
select distinct *name* from view1
--> name1
name2
name3
name4...
Now in the second column, there should be numbers, which depend on this number:
select max(number) number_max from view2
--> 17
Now I want the second column to be ascending, depending on that number. The list of numbers for each name. The table should look like:
name1 18 ->(number_max+1)
name1 19 ->(number_max+2)
name1 20
name2 18
name2 19
name2 20
name3 18
....
How do I do this? Thank you so much!

This is how I understood it:
Sample data (your views, view1 and view2, simplified):
SQL> with
2 view1 (name) as
3 (select 'name1' from dual union all
4 select 'name1' from dual union all
5 select 'name1' from dual union all
6 select 'name2' from dual union all
7 select 'name3' from dual union all
8 select 'name3' from dual
9 ),
10 view2 (c_number) as
11 (select 15 from dual union all
12 select 17 from dual
13 )
14 --
Query begins here; subquery that is cross-joined to view1 just fetches the maximum number column value which is then added to result of the row_number analytic function that partitions data per each name:
15 select
16 a.name as col1,
17 row_number() over (partition by a.name order by null) + b.number_max as col2
18 from view1 a cross join (select max(c_number) number_max from view2) b
19 order by 1, 2;
COL1 COL2
----- ----------
name1 18
name1 19
name1 20
name2 18
name3 18
name3 19
6 rows selected.
SQL>

You can use GROUP BY name to find the DISTINCT names and find the maximum maximum by nesting an MAX aggregation function inside a MAX analytic function and then CROSS JOIN to a row-generator.
For example, if you wanted 3 rows for each name:
SELECT m.name,
m.number_max + l.value AS value
FROM ( SELECT name,
MAX(MAX("NUMBER")) OVER () AS number_max
FROM table_name
GROUP BY name
) m
CROSS JOIN (
SELECT LEVEL AS value FROM DUAL CONNECT BY LEVEL <= 3
) l;
Which, if you have the sample data:
CREATE TABLE table_name (name, "NUMBER") AS
SELECT 'name1', 17 FROM DUAL UNION ALL
SELECT 'name1', 1 FROM DUAL UNION ALL
SELECT 'name1', 7 FROM DUAL UNION ALL
SELECT 'name2', 15 FROM DUAL UNION ALL
SELECT 'name2', 15 FROM DUAL UNION ALL
SELECT 'name3', 5 FROM DUAL UNION ALL
SELECT 'name3', 7 FROM DUAL UNION ALL
SELECT 'name4', 2 FROM DUAL UNION ALL
SELECT 'name4', 1 FROM DUAL;
Outputs:
NAME
VALUE
name1
18
name2
18
name3
18
name4
18
name1
19
name2
19
name3
19
name4
19
name1
20
name2
20
name3
20
name4
20
db<>fiddle here

Related

How can I select a data from another column from rows that have been selected?

I tried my best to figure and google this out, but couldn't really find a solid answer to it.
The problem I'm facing is that
Table 1:
ID Value 1
1 a
2 b
3 c
Table 2:
ID Value 2
1 4a
3 5b
4 6c
and I'd basically have to select the value from Table 1 that doesn't exist on Table 2 (Thus, 'b')
I can select and identify the ID that I want by using minus function between the tables, but can't seem to figure out a way to call a query to instead call the data.
Use the MINUS as a subquery (i.e. an inline view) (lines #14 - 16):
Sample data:
SQL> with
2 table1(id, value1) as
3 (select 1, 'a' from dual union all
4 select 2, 'b' from dual union all
5 select 3, 'c' from dual
6 ),
7 table2 (id, value2) as
8 (select 1, '4a' from dual union all
9 select 3, '5b' from dual union all
10 select 4, '6c' from dual
11 )
Query begins here:
12 select a.*
13 from table1 a
14 where a.id in (select t1.id from table1 t1
15 minus
16 select t2.id from table2 t2
17 );
ID VALUE1
---------- ----------
2 b
SQL>
Alternatively, use not exists:
<snip>
12 select a.*
13 from table1 a
14 where not exists (select null
15 from table2 b
16 where b.id = a.id
17 );
ID VALUE1
---------- ----------
2 b
SQL>

select only those users whose contacts length is not 5

I have table like this:
id
name
contact
1
A
65489
1
A
1
A
45564
2
B
3
C
12345
3
C
1234
4
D
32
4
D
324
I only want users who have no contact or the contact length is not five.
If the user has two or more contacts and the length of one of them is five and the rest is not, then such users should not be included in the table.
so,If the customer has at least one contact length of five, I do not want that.
so, i want table like this:
id
name
contact
2
B
4
D
32
4
D
324
Can you halp me?
You could actually do a range check here:
SELECT id, name, contact
FROM yourTable t1
WHERE NOT EXISTS (
SELECT 1
FROM yourTable t2
WHERE t2.id = t1.id AND TO_NUMBER(t2.contact) BETWEEN 10000 AND 99999
);
Note that if contact already be a numeric column, then just remove the calls to TO_NUMBER above and compare directly.
Yet another option:
SQL> with test (id, name, contact) as
2 (select 1, 'a', 65879 from dual union all
3 select 1, 'a', null from dual union all
4 select 1, 'a', 45564 from dual union all
5 select 2, 'b', null from dual union all
6 select 3, 'c', 12345 from dual union all
7 select 3, 'c', 1234 from dual union all
8 select 4, 'd', 32 from dual union all
9 select 4, 'd', 324 from dual
10 )
11 select *
12 from test a
13 where exists (select null
14 from test b
15 where b.id = a.id
16 group by b.id
17 having nvl(max(length(b.contact)), 0) < 5
18 );
ID N CONTACT
---------- - ----------
2 b
4 d 32
4 d 324
SQL>
COUNT analytic function can also be used to get the job done.
select id, name, contact
from (
select id, name, contact
, count( decode( length(contact), 5, 1, null ) ) over( partition by id, name ) cnt
from YourTable
)
where cnt = 0
demo

Conditional union in Oracle query

I have a query which gives me 2 columns,
select
name as name,
code as code
from
table1
UNION
select
name as name,
code as code
from
table2
I would like to apply one more union in the result if from the above query i did not get a row with name as 'Default'. So if above query didnt have a record with default name i need to have 1 more union with above query:
select
'Default' as name,
code as code
from
table1
where condition = condition
I tried putting first query in a view and use not exists function in second query but it gives column not found error.
This is how I understood the question: lines #1 - 9 represent sample data; one of rows contains the Default name, so your resulting query should return the union-ed result as is:
SQL> with
2 table1 (name, code) as
3 (select 'Little', 1 from dual union all
4 select 'Foot' , 2 from dual
5 ),
6 table2 (name, code) as
7 (select 'Default', 3 from dual union all --> Default is here
8 select 'Oracle' , 4 from dual
9 ),
10 -- the "original" union
11 oriun as
12 (select name, code from table1
13 union
14 select name, code from table2
15 )
16 select name, code from oriun
17 union
18 select 'Default' name, null code from table1
19 where not exists (select null from oriun
20 where name = 'Default'
21 )
22 order by code;
NAME CODE
------- ----------
Little 1
Foot 2
Default 3
Oracle 4
SQL>
But, if there's no Default in those tables (see change made in line #7), then you'd get an "extra" Default row:
SQL> with
2 table1 (name, code) as
3 (select 'Little', 1 from dual union all
4 select 'Foot' , 2 from dual
5 ),
6 table2 (name, code) as
7 (select 'xxx', 3 from dual union all --> No more Default here
8 select 'Oracle' , 4 from dual
9 ),
10 -- the "original" union
11 oriun as
12 (select name, code from table1
13 union
14 select name, code from table2
15 )
16 select name, code from oriun
17 union
18 select 'Default' name, null code from table1
19 where not exists (select null from oriun
20 where name = 'Default'
21 )
22 order by code;
NAME CODE
------- ----------
Little 1
Foot 2
xxx 3
Oracle 4
Default
SQL>
When you have order by in union you need to put it inside a view or create a block with select * from (.. order by)

Print message when no data is found

Need a query to get the Employee name, total fuel used by each employee.
If fuel is not used by an employee then the second column should have a
text “No fuel used”.
These are the following two tables:
Table1: EmployeeID, FirstName
1 Vikas
2 nikita
3 Ashish
4 Nikhil
5 anish
Table2: ID, Fuel
1 10
2 9
3 8
4 6
5 12
6 11
7 10
8 9
9 8
10 10
11 9
12 12
13 7
14 15
where The column table2.ID is a foreign key to table1.EmployeeID.
This is code which I have written, Which is most probably wrong.
select ID, FirstName, sum(table2.Fuel) sum_fuel
from table2,table1
where EmployeeID=ID IN (
select ID, coalesce(ID, 'No-fuel used') as ID
from table1 t1
left join table2 t2 on t2.ID = t1.EmployeeID
)
group by fuel
order by ID DESC;
As you can see from two tables that employee with from 1 to 5 of table1 are in table2. So for these employee I need to show total fuel used by every individual. And for employee with ID from 6 to 14 are not available in table1 so for these employee “No fuel used” message should be printed.
You can use a left join. This way, whenever the Id values for tables don't match you'll get null values for sum(fuel) value, and will assign the string 'No fuel used'for sum_fuel column by using nvl() function:
with table1( EmployeeID, FirstName ) as
(
select 1,'Vikas' from dual union all
select 2,'nikita' from dual union all
select 3,'Ashish' from dual union all
select 4,'Nikhil' from dual union all
select 5,'anish' from dual union all
select 15,'pratteek' from dual
), table2( ID, Fuel ) as
(
select 1, 10 from dual union all
select 2, 9 from dual union all
select 3, 8 from dual union all
select 4, 6 from dual union all
select 5, 12 from dual union all
select 6, 11 from dual union all
select 7, 10 from dual union all
select 8, 9 from dual union all
select 9, 8 from dual union all
select 10, 10 from dual union all
select 11, 9 from dual union all
select 12, 12 from dual union all
select 13, 7 from dual union all
select 14, 15 from dual
)
select EmployeeID, FirstName, nvl(to_char(sum(t2.Fuel)),'No fuel used') as sum_fuel
from table1 t1
left join table2 t2
on t1.EmployeeID = t2.ID
group by EmployeeID, FirstName
order by EmployeeID desc;
EMPLOYEEID FIRSTNAME SUM_FUEL
---------- --------- ------------
15 pratteek No fuel used
5 anish 12
4 Nikhil 6
3 Ashish 8
2 nikita 9
1 Vikas 10
Demo
This may work---
SELECT ID
, FirstName
, CASE
WHEN SUM(f.Fuel) > 0 THEN CAST(SUM(f.Fuel) AS NVARCHAR(25))
ELSE 'No fuel used'
END sum_fuel
FROM #emp e
LEFT JOIN #fuel f ON e.EmployeeID = f.id
GROUP BY ID,FirstName
ORDER BY ID DESC

How to sort alphanumeric String in oracle?

Input is:
Section1
Section2
Section3
Section10
Section11
Section1A
Section1B
Section12
Section11A
Section11B
And I want output like:
Section1
Section1A
Section1B
Section2
Section3
Section10
Section11
Section11A
Section11B
Section12
I tried query :
select section_name
from sections
order by length(section_name),section_name
Assuming that the structure of your strings is fixed, as in your example, this could be a way:
SQL> select x,
2 to_number(regexp_substr(x, '[0-9]+')) numericPart,
3 regexp_substr(x, '([0-9]+)([A-Z])', 1, 1, '', 2) optionalChar
4 from (
5 select 'Section1' x from dual union all
6 select 'Section2' from dual union all
7 select 'Section3' from dual union all
8 select 'Section10' from dual union all
9 select 'Section11' from dual union all
10 select 'Section1A' from dual union all
11 select 'Section1B' from dual union all
12 select 'Section12' from dual union all
13 select 'Section11A' from dual union all
14 select 'Section11B' from dual
15 )
16 order by numericPart,
17 optionalChar nulls first
18 ;
X NUMERICPART OPTIONALCHAR
---------- ----------- ----------------------------------------
Section1 1
Section1A 1 A
Section1B 1 B
Section2 2
Section3 3
Section10 10
Section11 11
Section11A 11 A
Section11B 11 B
Section12 12
Here you first order by the numeric part, treating it as number, and then consider the (optional) character after the number.