I have this simple table.
City Country State Id
Great Falls (null) VA 12345
Great Falls USA VA 12345
I wanted to use CONCAT function for City + Country + State with running code below in Oracle environment.
SELECT City, Country, State,
City ||', ' ||Country|| ', '||State AS Concat_fields
FROM #TEMP
City Country State Concat_fields Id
Great Falls (null) VA Great Falls, , VA 12345
Great Falls USA VA Great Falls, USA, VA 12345
Question: is there a better that the query can altered in such a way that it returns only 1 record? I wanted to show my result like this:
City Country State Concat_fields Id
Great Falls USA VA Great Falls, USA, VA 12345
Any thoughts, criticisms, suggestions?
If the only difference between the rows are null vs. non-null values, then you can use an aggregate before concatenating:
-- CTE for sample data
with "#TEMP" (city, country, state, id) as (
select 'Great Falls', null, 'VA', 12345 from dual
union all select 'Great Falls', 'USA', 'VA', 12345 from dual
)
-- actual query
select max(city) as city, max(country) as country, max(state) as state,
max(city) ||', ' ||max(country)|| ', '||max(state) as concat_fields
from "#TEMP"
group by id;
CITY COU ST CONCAT_FIELDS
----------- --- -- --------------------
Great Falls USA VA Great Falls, USA, VA
If the rows for an ID have different non-null values then that obviously won't work:
with "#TEMP" (city, country, state, id) as (
select 'Great Falls', null, 'VA', 12345 from dual
union all select 'London', 'UK', null, 12345 from dual
)
select max(city) as city, max(country) as country, max(state) as state,
max(city) ||', ' ||max(country)|| ', '||max(state) as concat_fields
from "#TEMP";
CITY CO ST CONCAT_FIELDS
----------- -- -- -------------------
London UK VA London, UK, VA
but then you would need some way to determine which row is correct - e.g. from a sequence or date column if this represents a history of addresses for a customer and you want the 'latest' version. The trick then is knowing how to determine which is 'latest'.
SELECT City, Country, State,
City ||', ' ||Country|| ', '||State AS Concat_fields
FROM #TEMP
WHERE Country IS NOT NULL
This will work for the provided dataset.
Generally speaking though Ids are unique (primary key), so make sure you are building your table in a way that adheres to more accepted database practices.
Related
data in student table:
STUDENT_NAME STUDENT_ID ADDRESS
------------ ----------- --------
Anandhi 1 4th street
Anitha 4 Cross cut
david 7 Main Cross Street
Kokila 8 Rao Street
Mithali 9 OMR road
I have tried the query:
select student_id,address from student where student_name='david';
Expected Output:
STDENT_ID ADDRESS
---------- ----------
7 Main Cross Street
I have tried the following code, it executes successfully and gives the desired result, however it fails to clear one test case and IDK why?
You may try lowercasing the student name column, then compare it to david in all lowercase.
SELECT ADDRESS
FROM student
WHERE LOWER(STUDENT_NAME) = 'david';
Are you sure all student names are stored in LOWERCASE?
Second, is it all rows in your question present in the table or is it a subset?
If the answer is NO and it is a subset
then try
SELECT student_id,address FROM student WHERE LOWER(student_name) = 'david';
And if you are not sure about leading and trailing spaces
then try
SELECT student_id,address FROM student WHERE TRIM(LOWER(student_name)) = 'david';
Actual Oracle versions currently supported (12.1.0.2 is EOL already) have collate clause, so since Oracle 12.2 you can use collate clause on different levels: Column level, table level, schema level, database level, session level, query level:
https://oracle-base.com/articles/12c/column-level-collation-and-case-insensitive-database-12cr2
For example, for your case:
SELECT student_id,address FROM student WHERE student_name collate BINARY_AI = 'david';
Full test case with test data and results:
--test data:
with STUDENT(STUDENT_NAME,STUDENT_ID,ADDRESS) as
(
select 'Anandhi' , 1, '4th street' from dual union all
select 'Anitha' , 4, 'Cross cut' from dual union all
select 'david' , 7, 'Main Cross Street' from dual union all
select 'Kokila' , 8, 'Rao Street' from dual union all
select 'Mithali' , 9, 'OMR road' from dual
) -- end of test data
-- main query:
SELECT student_id,address FROM student WHERE student_name collate BINARY_AI = 'david';
-- Results:
STUDENT_ID ADDRESS
---------- -----------------
7 Main Cross Street
I am trying to get first distinct 3 columns while the last column can have any value. If i do distinct on all columns then it gives me 8 rows. This table is dynamic so i will need distinct 3 columns and any value in the last column.
I have the following scenerio,
Name Surname Road Pet
John Trav John_road dog
Kaley Couco Couco_road horse
Charlie Sheen Sheen_road rabbit
Johnny Galecki Galecki_road cat
John Trav John_road donkie
Kaley Couco Couco_road mouse
Charlie Sheen Sheen_road goat
Johnny Galecki Galecki_road pig
Desired result:
Name Surname Road Pet
John Trav John_road dog
Kaley Couco Couco_road mouse
Charlie Sheen Sheen_road rabbit
Johnny Galecki Galecki_road cat
I tried the solution on this link but it is not working:
Oracle 11g SQL to get unique values in one column of a multi-column query
Please help in Oracle
As you don't care about the last column value, a simple option is to aggregate it as
select name, surname, road, max(pet)
from your_table
group by name, surname, road
Use row_number() with partition by first three columns:
dbfiddle demo
select *
from (
select t.*,
row_number() over (partition by Name, Surname, Road order by pet) rn
from t)
where rn = 1
Did you try this
SELECT NAME, SURNAME, rOAD, PET FROM
(
SELECT NAME, SURNAME, rOAD, PET, ROW_NUMBER () OVER (PARTITION BY NAME, SURNAME, rOAD ORDER BY PET) RN FROM FROM TABLE_NAME
) WHERE RN=1
I have the following tables
f_orders
ORDER_NUMBER NUMBER(5,0)
ORDER_DATE DATE
ORDER_TOTAL NUMBER(8,2)
CUST_ID NUMBER(5,0)
STAFF_ID NUMBER(5,0)
with the following data
ORDER_NUMBER ORDER_DATE ORDER_TOTAL CUST_ID STAFF_ID
5678 10-Dec-2017 103.02 123 12
9999 10-Dec-2017 10 456 19
9997 09-Dec-2017 3 123 19
9989 10-Dec-2016 3 123 19
and
f_customers
ID NUMBER(5,0)
FIRST_NAME VARCHAR2(25)
LAST_NAME VARCHAR2(35)
ADDRESS VARCHAR2(50)
with the following data
ID FIRST_NAME LAST_NAME ADDRESS
123 Cole Bee 123 Main Street
456 Zoe Twee 1009 Oliver Avenue
I'm supposed to display the name of the customer wthi the most orders placed in the year 2017.
My query looks like this
SELECT f_customers.first_name,
f_customers.last_name,
count(order_total)
FROM f_orders JOIN f_customers
ON f_customers.id = f_orders.CUST_ID
WHERE TO_CHAR(order_date, 'DD-Mon-YYYY') LIKE '%2017'
GROUP BY f_customers.first_name, f_customers.last_name
HAVING count(order_total) = (SELECT max(count(cust_id))
FROM f_orders
GROUP BY cust_id)
The problem is that whenever I insert the where statement it returns no data found, even though it should return the name Cole Bee with 2 orders
If I remove the where statement it will show that Cole Bee has placed 3 orders
I can't figure out why I get the no data found result. Any ideas?
Your main query is filtering on the year; the subquery on the right hand side of the having clause is not. The max(count()) is 3 if you run that subquery on its own, and you’re comparing that with the filtered list which (as you expect) only finds 2 rows for that customer.
Run the whole query with just the having part removed (rather than the where clause), and run just the subquery; and compare the results.
The simple answer is to repeat the filter:
SELECT f_customers.first_name,
f_customers.last_name,
count(order_total)
FROM f_orders JOIN f_customers
ON f_customers.id = f_orders.CUST_ID
WHERE TO_CHAR(order_date, 'DD-Mon-YYYY') LIKE '%2017'
GROUP BY f_customers.first_name, f_customers.last_name
HAVING count(order_total) = (SELECT max(count(cust_id))
FROM f_orders
WHERE TO_CHAR(order_date, 'DD-Mon-YYYY') LIKE '%2017'
GROUP BY cust_id)
Both filters could be written more simply as:
WHERE TO_CHAR(order_date, 'YYYY') = '2017'
or even:
WHERE EXTRACT(YEAR FROM order_date) = 2017
You can avoid hitting the table twice using analytic queries and other tricks but as this seems to be an assignment that may be getting beyond what you’ve been taught and are expected to know/use.
I have a table ctry in Oracle Database schema.This table has columns country_name,city_name,city_id,site_name,site_id...
My requirement is to get the distinct city Id and city name for a particular country.
So my query,
SELECT distinct(city_Id), city_name from ctry where country_name = "somevalue".
gives me the required results.
To this resultant list I would want to add a row having values as
city_id = "(offsite)" and city_name= "OFF site"(which is not there in the table.)
I have used query like
SELECT distinct(city_Id), city_name from ctry where country_name = "somevalue".
union
select '(offsite)' AS city_Id, 'OFF SITE' AS city_name from ctry
But here the problem is the resultant list will have multiple values of city_id and city_name as '(offsite)' and 'OFF SITE' respectively.
But I would only want one row with Offsite Values.Is there any way i can achieve this?
Thanks in advance.
As your are not reading data from ctry, you can just use dual table
SELECT distinct(city_Id), city_name from ctry where country_name = "somevalue".
union select '(offsite)' AS city_Id, 'OFF SITE' AS city_name from dual
This is from Oracle Database 10g: SQL Fundamentals.
Original Oracle textbook.
Francly speaking, this all is actual so far.
There is a task which troubles me:
Display the last name, department name, and salary of any employee whose salary and commission match the salary and commission of many employee located in location ID 1700.
The topic to be learned is multiple column subqueries. This mean that we can't deviate from the offered model which is:
SELECT column, column, ...
FROM table
WHERE (column, column, ...) IN
(SELECT column, column, ...
FROM table
WHERE condition);
Well, my database:
describe employees
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
describe departments
Name Null Type
--------------- -------- ------------
DEPARTMENT_ID NOT NULL NUMBER(4)
DEPARTMENT_NAME NOT NULL VARCHAR2(30)
MANAGER_ID NUMBER(6)
LOCATION_ID NUMBER(4)
There is a solution:
select
e.last_name,
d.department_name,
e.salary
from employees e, departments d
where e.department_id = d.department_id
and (salary, nvl(commission_pct, 0)) in
(select salary, nvl(commission_pct, 0)
from employees e, departments d
where e.department_id = d.department_id
and d.location_id = 1700);
SELECTED 36 ROWS.
Well, I started checking. It seems that employees from location 1700 duplicated against themselves.
Look: we take the whole list of employees and then juxtapose it with employees from location 1700. Of course, there will be duplicates.
I have prepared an excel file with some data (all employees, employees from location 1700, the result of my own desired result etc.). In the file it is more picturesque, with examples and so on. Please, have a look.
This is the file: https://skydrive.live.com/redir?resid=8CDFFBA921B002FE!150&authkey=!ADMRAE466BIunQM
Well, what I would like to do is to control that no employee is compared with themselves.
This was my variant bevore I checked the solution.
select lnme, dpt, slry
from
(
select
employee_id eid,
last_name lnme,
salary slry,
nvl(commission_pct,0) cpct,
d.department_name dpt,
location_id
from employees e
left join departments d
on e.department_id = d.department_id
)
where (slry, cpct) in
(select
employee_id ide,
salary slry,
nvl(commission_pct,0) cpct
from employees e
join departments d
on e.department_id = d.department_id and location_id = 1700)
and ide <> eid
I wanted to make sure that no employee is compared with the same employee. But I failed.
Could you comment on all this situation:
1. Whether I'm completely wrong and the solution of Oracle is perfect.
2. If Oracle is wrong, could you help me with this code?
Thank you in advance.
The question asks you to identify any employee whose salary and commission matches any combination of salary and salary of employees in Department 1700. The question doesn't say to exclude employees from that department. So it is quite correct for them to appear in the result set.
"One employee can't match themselves."
You're not matching employees, you're matching salaries . It just so happens that the list of target salaries is generated from a sub-query on department 1700: it could just as easily be a list of numbers from a CSV file.
Let's have a thought experiment. There are three employees in department 1700:
name | salary | comm
-----------+---------+-----
CHIP | 10,100 | 0
RUNCITER | 12,200 | 0
CONLEY | 10,500 | 0
Nobody else in the company earns above 10K.
So what is the answer to the question: how many employee have a salary and commission which match the salary and commission of any employee located in department 1700?
Three
Zero
Then Joe gets a modest raise and the salaries look like this:
name | salary | comm
-----------+---------+-----
CHIP | 10,500 | 0
RUNCITER | 12,200 | 0
CONLEY | 10,500 | 0
So what is the answer to the same question now?
Still three
Two
The answer is 'three' in both cases.
Why?
Because SQL is a set-based programming language, and the set of all employees who earn the exact salary and commission as employees in department 1700 must include all employees who work in department 1700.
There is a different set, which is the set of all employees who earn the exact salary and commission as employees in department 1700 who don't themselves work in department 1700. But that is not the set the SQL Fundamentals quiz is looking for.