This question already has answers here:
How to find the city name not starting and ending with a vowel
(5 answers)
Closed last month.
i do this
select distinct city
from station
where regexp_like(city,'^[^aeiou].*[^aeiou]$','i') and regexp_like(city,'^[^aeiou]\w+[^aeiou]$','i');
. it is wrong i know. but can someone explain to me where i am wrong at based on the question ? any answer will appreciated. thank you.
here link screenshot from the question.
Does it have to be regex? substr handles it in a simple manner:
SQL> with station (city) as
2 (select 'Zagreb' from dual union all
3 select 'Athens' from dual union all
4 select 'Rome' from dual union all
5 select 'Ottawa' from dual
6 )
7 select distinct city
8 from station
9 where upper(substr(city, 1, 1)) not in ('A', 'E', 'I', 'O', 'U')
10 and upper(substr(city, -1)) not in ('A', 'E', 'I', 'O', 'U');
CITY
------
Zagreb
SQL>
If you must use regex, then
7 select distinct city
8 from station
9 where regexp_like(city, '^[^aeiou].*[^aeiou]$', 'i');
CITY
------
Zagreb
SQL>
Related
Noob question. I'm writing a script to execute a report showing:
Student last name and first name (comma separated), years enrolled, academic advisor last name and first name (comma separated)
Sort: years enrolled
Filter: only include currently active students
Struggling with calculating years enrolled and filtering by active students.
The tables I'm using:
SELECT CONCAT(CONCAT(Student.Last_Name, ', '), Student.First_Name) AS "Student",
Student_Enrollment_Status.Date_Status_Updated,
CONCAT(CONCAT(Faculty.Last_Name, ', '), Faculty.First_Name) AS "Advisor"
FROM Student
WHERE Faculty.Faculty_ID = Student.Advisor_ID
AND Student(Student_ID) = Student_Enrollment_Status(Student_ID)
AND Student_Enrollment_Status(Status_ID) = Enrollment_Status (Status_ID);
It would be something like this:
lines #1 - 22 represent sample data (you don't type that)
query you need begins at line #24
years enrolled is calculated by subtracting current year and year of enrollment; that's rather inaccurate, but - you didn't explain what exactly it means
I presumed that active statuses are IDs (2, 3, 5)
SQL> with
2 student (student_id, first_name, last_name, advisor_id) as
3 (select 1, 'ash', 'smith', 9 from dual union all
4 select 2, 'tash', 'paul', 8 from dual union all
5 select 3, 'carl', 'wall', 6 from dual union all
6 select 4, 'fred', 'john', 3 from dual),
7 student_enrollment_status (student_id, status_id, date_status_updated) as
8 (select 1, 2, date '2017-09-04' from dual union all
9 select 2, 3, date '2018-09-05' from dual union all
10 select 3, 3, date '2018-09-05' from dual union all
11 select 4, 2, date '2019-09-04' from dual),
12 enrollment_status (status_id, status) as
13 (select 2, 'enrolled' from dual union all
14 select 3, 'on leave' from dual union all
15 select 4, 'full time' from dual union all
16 select 5, 'part time' from dual union all
17 select 6, 'withdrawn' from dual),
18 faculty (faculty_id, first_name, last_name) as
19 (select 9, 'jane', 'gold' from dual union all
20 select 8, 'sam', 'greene' from dual union all
21 select 6, 'mark', 'west' from dual union all
22 select 3, 'jen', 'dash' from dual)
23 --
24 select s.last_name ||', '|| s.first_name student,
25 extract(year from sysdate) - extract(year from ses.date_status_updated)
26 years_enrolled,
27 f.last_name ||', '|| f.first_name advisor
28 from student s join student_enrollment_status ses on ses.student_id = s.student_id
29 join enrollment_status es on es.status_id = ses.status_id
30 join faculty f on f.faculty_id = s.advisor_id
31 where es.status_id in (2, 3, 5)
32 order by years_enrolled;
STUDENT YEARS_ENROLLED ADVISOR
----------- -------------- ------------
john, fred 1 dash, jen
paul, tash 2 greene, sam
wall, carl 2 west, mark
smith, ash 3 gold, jane
SQL>
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I'm having a two columns say Value column is having records like 'abc|comp|science|raja' and I want to split this records like abc,comp,science,raja and I need to compare it with another column say CHECKER which is having record as science
Value
abc|comp|science|raja
Checkers
science
You don't need to split the string and you don't even need a regular expression; just check whether the checker string (with leading a trailing delimiters) is a sub-string of value (with leading and trailing delimiters):
Oracle Setup:
CREATE TABLE your_table ( value, checker ) as
SELECT 'abc|comp|science|raja', 'science' FROM DUAL UNION ALL
SELECT 'abc|def|ghi', 'xyz' FROM DUAL UNION ALL
SELECT 'abc', 'abc' FROM DUAL UNION ALL
SELECT 'abcdef', 'abc' FROM DUAL
Query:
SELECT *
FROM your_table
WHERE '|' || value || '|' LIKE '%|' || checker || '|%';
Output:
VALUE | CHECKER
:-------------------- | :------
abc|comp|science|raja | science
abc | abc
db<>fiddle here
You can split your pipe delimited string in individual values and represent that as a table. Then you can just join to your Checkers table.
The web is full of examples, here are 2 ways to do it.
The REGEXP way...
WITH test_tab AS
(SELECT 'abc|comp|science|raja' str FROM dual
)
SELECT regexp_substr (str, '[^|]+', 1, rownum) split
FROM test_tab
CONNECT BY LEVEL <= LENGTH (regexp_replace (str, '[^|]+')) + 1;
If you have Application Express in your database, you can use apex_string to do the magic for you:
SELECT
column_value
FROM
TABLE(apex_string.split(
'abc|comp|science|raja',
'|'
));
Here's one option:
SQL> with test (id, value, checkers) as
2 (select 1, 'abc|comp|science|raja', 'science' from dual union all
3 select 2, 'xyz|bla|nothing' , 'zzz' from dual
4 )
5 select t.id,
6 regexp_substr(t.value, '[^\|]+', 1, column_value) val,
7 column_value rn,
8 t.checkers,
9 --
10 case when regexp_substr(t.value, '[^\|]+', 1, column_value) = t.checkers then 'Match'
11 else 'No match'
12 end what
13 from test t cross join table(cast(multiset(select level from dual
14 connect by level <= regexp_count(t.value, '\|') + 1
15 ) as sys.odcinumberlist))
16 order by t.id, rn;
ID VAL RN CHECKER WHAT
---------- --------------------- ---------- ------- --------
1 abc 1 science No match
1 comp 2 science No match
1 science 3 science Match
1 raja 4 science No match
2 xyz 1 zzz No match
2 bla 2 zzz No match
2 nothing 3 zzz No match
7 rows selected.
SQL>
It sounds like you just want to check whether the checker is in the value, in that case you can do this:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual )
select x.value
from mytable x
where regexp_like(value, '(^|\|)' || checker || '($|\|)')
The regex_like is searching inside the value for the checker with either a pipe or the end of the string, so it will match the keyword at the beginning, in the middle or at the end of the string. But it would not match "sciences".
Alternatively if you want to see all the rows and check whether they passed the "check" you could do:
with mytable as
( select 'abc|comp|science|raja' value
, 'science' as checker
from dual
union all
select 'science|abc|comp|raja'
, 'science'
from dual
union all
select 'abc|comp|raja|science'
, 'science'
from dual
union all
select 'abc|comp|raja|sciences'
, 'science'
from dual )
select x.value
, x.checker
, case when regexp_substr(value, '(^|\|)' || checker || '($|\|)') is not null
then 'Y'
end as passed
from mytable x
What I'm trying to do is a list of persons from a table and in the event where a person exists more than once then return back their record that contains the highest ranked 'code'
Code ranking (high to low): T, E, F
So for the given dataset
Person Code
----------------
Tom F
Paul E
Mark F
Paul T
Mark E
Chris T
Chris E
I would get the following back from my query
Person Code
----------------
Tom F
Paul T
Mark E
Chris T
I'm assuming this is going to use the rank/analytic functions, but I'm just not familiar enough with them.
Thanks!
You can use the RANK function to rank the data
SQL> ed
Wrote file afiedt.buf
1 with data as (
2 select 'Tom' person, 'F' code from dual union all
3 select 'Paul', 'E' from dual union all
4 select 'Paul', 'T' from dual union all
5 select 'Mark', 'F' from dual union all
6 select 'Mark', 'E' from dual
7 )
8 select *
9 from (select person,
10 code,
11 rank() over (partition by person
12 order by (case when code='T' then 1
13 when code='E' then 2
14 when code='F' then 3
15 else null
16 end)) rnk
17* from data)
SQL> /
PERS C RNK
---- - ----------
Mark E 1
Mark F 2
Paul T 1
Paul E 2
Tom F 1
Elapsed: 00:00:00.00
Then, you just need to select the rows with a RNK of 1
SQL> ed
Wrote file afiedt.buf
1 with data as (
2 select 'Tom' person, 'F' code from dual union all
3 select 'Paul', 'E' from dual union all
4 select 'Paul', 'T' from dual union all
5 select 'Mark', 'F' from dual union all
6 select 'Mark', 'E' from dual
7 )
8 select *
9 from (select person,
10 code,
11 rank() over (partition by person
12 order by (case when code='T' then 1
13 when code='E' then 2
14 when code='F' then 3
15 else null
16 end)) rnk
17 from data)
18* where rnk = 1
SQL> /
PERS C RNK
---- - ----------
Mark E 1
Paul T 1
Tom F 1
Elapsed: 00:00:00.00
The shortest and most performant and Oracle specific solution:
SQL> create table mytable(person,code)
2 as
3 select 'Tom', 'F' from dual union all
4 select 'Paul', 'E' from dual union all
5 select 'Mark', 'F' from dual union all
6 select 'Paul', 'T' from dual union all
7 select 'Mark', 'E' from dual union all
8 select 'Chris', 'T' from dual union all
9 select 'Chris', 'E' from dual
10 /
Table created.
SQL> select person
2 , max(code) keep (dense_rank first order by decode(code,'T',1,'E',2,'F',3,4)) code
3 from mytable
4 group by person
5 /
PERSO C
----- -
Chris T
Mark E
Paul T
Tom F
4 rows selected.
Regards,
Rob.
i don't think RANK is what you need...
basically, your delete will look like this: (pseudo-query)
delete the rows from person
where that row is not in ( select the rows from person with the highest code )
edit:
this trick might help you too:
select person, code, decode( code, 'T', 1, 'E', 2, 'F', 3, 0 ) from mytable
Hum... Alternative suggestion with standard SQL.
Have a CODE_WEIGHT table such as:
CODE WEIGHT
T 3
E 2
F 1
Then group your query by Person (if this is the grouping criterion) and select the distinct code containing max(weight).
I'll post the query in a couple of minutes.
UPDATE
Ok, sorry for the delay.
Here is a solution using the previous stated table and #Randy trick:
SELECT
pp.person, decode(max(c.weight), 3, 'T', 2, 'E', 1, 'F', '') code
FROM
person pp INNER JOIN code_weight c on (pp.code = c.code)
GROUP BY
pp.person
ORDER BY
person DESC;
I'm pretty sure there is a way to dump Oracle proprietary function and get things done in pure SQL... Anyway, since you've asked for a Oracle solution, here it is.
UPDATE 2
And as promised, here's the best standard SQL version that I was able to come up with:
SELECT
p.person, c.code
FROM
(
SELECT
pp.person, MAX(cc.weight) weight
FROM
person pp INNER JOIN code_weight cc ON (pp.code = cc.code)
GROUP BY
pp.person
) p INNER JOIN code_WEIGHT c ON (p.weight = c.weight)
ORDER BY
p.person DESC;
Kinda ugly with the two joins... But it does the job without proprietary extensions. Any SQL guru knows how to optimize it?
Cheers,
I'm not 100% if tuples is the term for what I'm talking about but I'm looking at something like this:
Table grades
user grade
------------
Jim B
Bill C
Tim A
Jim B+
I know I can do:
SELECT COUNT(*)
FROM grades
WHERE (
(user = 'Jim' AND grade = 'B')
OR (user = 'Tim' AND grade = 'C')
);
But is there a way to do something more like this?
SELECT COUNT(*)
FROM grades
WHERE (user, grade) IN (('Jim','B'), ('Tim','C'));
EDIT: As a side note, I'd only tested with:
(user, grade) = ('Tim','C')
And that fails, so I assumed IN would fail as well, but I was wrong (thankfully!).
The query you posted should be valid syntax
SQL> ed
Wrote file afiedt.buf
1 with grades as (
2 select 'Jim' usr, 'B' grade from dual
3 union all
4 select 'Bill', 'C' from dual
5 union all
6 select 'Tim', 'A' from dual
7 union all
8 select 'Jim', 'B+' from dual
9 )
10 select *
11 from grades
12 where (usr,grade) in (('Jim','B'),
13 ('Tim','C'),
14* ('Tim','A'))
SQL> /
USR GR
---- --
Jim B
Tim A
You could use a subquery to treat a list of tuples like a table:
SELECT COUNT(*)
FROM grades
JOIN (
SELECT 'Jim' as user, 'B' as grade from dual
UNION ALL
SELECT 'Tim', 'C' from dual
UNION ALL
SELECT 'Pim', 'D' from dual
) as SearchTarget
ON SearchTarget.user = grades.user
and SearchTarget.grade = grades.grade
I have some one-many normalized data that looks like this.
a | x
a | y
a | z
b | i
b | j
b | k
What query will return the data such that the "many" side is represented as a CSV string?
a | x,y,z
b | i,j,k
Mark,
If you are on version 11gR2, and who isn't :-), then you can use listagg
SQL> create table t (col1,col2)
2 as
3 select 'a', 'x' from dual union all
4 select 'a', 'y' from dual union all
5 select 'a', 'z' from dual union all
6 select 'b', 'i' from dual union all
7 select 'b', 'j' from dual union all
8 select 'b', 'k' from dual
9 /
Tabel is aangemaakt.
SQL> select col1
2 , listagg(col2,',') within group (order by col2) col2s
3 from t
4 group by col1
5 /
COL1 COL2S
----- ----------
a x,y,z
b i,j,k
2 rijen zijn geselecteerd.
If your version is not 11gR2, but higher than 10gR1, then I recommend using the model clause for this, as written here: http://rwijk.blogspot.com/2008/05/string-aggregation-with-model-clause.html
If lower than 10, then you can see several techniques in rexem's link to the oracle-base page, or in the link to the OTN-thread in the blogpost mentioned above.
Regards,
Rob.