Comparing two rows in Oracle DB and Showing Column Mismatch - sql

Table Columns: Id, Name, Age
First Rows:
select 11, 'James', 22 from dual;
This will return
11 James 22
Second Row:
select * from supplier where id=11`;
This will return
11 Vinod 25
Now I wanted to compare both rows:
11 James 22
11 Vinod 25
It should return the columns which has differences.
Name Mismatch
Age Mismatch
I am using 12c is there Built in feature in oracle which will solve this.
Or any other ways from which I can achieve the solution for the same.
Thanks In advance..
`

You can use join and decode (can use case alternatively) to find out if column value matches:
with cte(id, name, age) as (select 11, 'James', 22 from dual)
select
s.id,
decode(s.name, t.name, null, 'Name mismatch') name_check,
decode(s.age, t.age, null, 'Age mismatch') age_check
from supplier s
inner join cte t
on s.id = t.id
where s.id = 11;

Related

Find whether given conditions based records are matching or not in sql

I have a table and want to find out whether the given condition matches or not with existing table records. I tried with not exists but that doesn't work. What expression would fill the is_exists column like in the expected output below?
create table user1(id number, name varchar2(20), age number);
insert into user1 values(1, 'user1', 1);
insert into user1 values(1, 'user11', 11);
insert into user1 values(2, 'user2', 2);
insert into user1 values(2, 'user22', 22);
insert into user1 values(3, 'user3', 3);
insert into user1 values(4, 'user4', 4);
select id, age, is_exists
from user1
where id = 1 and age in (1, 11, 111);
Expected result:
id age is_exists
-- --- ---------
1 1 true
1 11 true
1 111 false
You need some kind of table for the three set of values; which you can build using select ... union all. Then use left join or exists:
with cte as (
select 1 as id, 1 as age from dual union all
select 1, 11 from dual union all
select 1, 111 from dual
)
select cte.*, case when exists (
select 1
from user1
where user1.id = cte.id and user1.age = cte.age
) then 'yes' else 'no' end is_exists
from cte
SQL is designed to return a subset or transformed set of data from the underlying database. For example, FROM specifies that you want all columns and rows from a particular table. The expression list in the SELECT statement narrows down the number of columns you need from this table. The WHERE statement narrows down the number of rows you receive.
Every row in the result set is based on one or more existing rows in the original data set. In either case the maximum result is always the data that exists in the table.
Because you want one row for the age in the result set, you need one row for the age in the query source. If you don't have a table, creating a temporary one with a series of UNION is a good approach.
This is the same as 'Salman A', but using LEFT JOIN whose result is CASE tested in Select clause. Basicaly, if there is not a join then there is not a matching record...
WITH
fltr AS
(
Select 1 "ID", 1 "AGE" From DUAL UNION
Select 1 "ID", 11 "AGE" From DUAL UNION
Select 1 "ID", 111 "AGE" From DUAL
)
SELECT
f.ID "ID", f.AGE "AGE",
CASE WHEN u.ID Is Not Null THEN 'YES' ELSE 'NO' END "IS_EXISTS"
FROM
fltr f
LEFT JOIN
USER1 u ON(u.ID = f.ID And u.AGE = f.AGE)
--
-- Result
--
-- ID AGE IS_EXISTS
-- 1 1 YES
-- 1 11 YES
-- 1 111 NO

LIMIT by distinct values in PostgreSQL

I have a table of contacts with phone numbers similar to this:
Name Phone
Alice 11
Alice 33
Bob 22
Bob 44
Charlie 12
Charlie 55
I can't figure out how to query such a table with LIMITing the rows not just by plain count but by distinct names. For example, if I had a magic LIMIT_BY clause, it would work like this:
SELECT * FROM "Contacts" ORDER BY "Phone" LIMIT_BY("Name") 1
Alice 11
Alice 33
-- ^ only the first contact
SELECT * FROM "Contacts" ORDER BY "Phone" LIMIT_BY("Name") 2
Alice 11
Charlie 12
Alice 33
Charlie 55
-- ^ now with Charlie because his phone 12 goes right after 11. Bob isn't here because he's third, beyond the limit
How could I achieve this result?
In other words, select all rows containing top N distinct Names ordered by Phone
I don't think that PostgreSQL provides any particularly efficient way to do this, but for 6 rows it doesn't need to be very efficient. You could do a subquery to compute which people you want to see, then join that subquery back against the full table.
select * from
"Contacts" join
(select name from "Contacts" group by name order by min(phone) limit 2) as limited
using (name)
You could put the subquery in an IN-list rather than a JOIN, but that often performs worse.
If you want all names that are in the first n rows, you can use in:
select t.*
from t
where t.name in (select t2.name
from t t2
order by t2.phone
limit 2
);
If you want the first n names by phone:
select t.*
from t
where t.name in (select t2.name
from t t2
group by t2.name
order by min(t2.phone)
limit 2
);
try this:
SELECT distinct X.name
,X.phone
FROM (
SELECT *
FROM (
SELECT name
,rn
FROM (
SELECT name
,phone
,row_number() OVER (
ORDER BY phone
) rn
FROM "Contacts"
) AA
) DD
WHERE rn <= 2 --rn is the "limit" variable
) EE
,"Contacts" X
WHERE EE.name = X.name
above seems to be working correctly on following dataset:
create table "Contacts" (name text, phone text);
insert into "Contacts" (name, phone) VALUES
('Alice', '11'),
('Alice', '33'),
('Bob', '22'),
('Bob', '44'),
('Charlie', '13'),
('Charlie', '55'),
('Dennis', '12'),
('Dennis', '66');

Specific format Join results on SQL Server

I have trawled the internet looking for a solution but nothing so far.
Here are 2 sample tables joined on SID/ID
SID Name Attendance Class
1 abc good 1A
2 xyz bad 1B
3 dsk good 1A
4 uij bad 1B
5 sss bad 1A
6 fff good 1D
7 ccc good 1A
ID Lesson Result
1 Read Pass-67%
1 Write Pass-89%
1 Sing Pass-99%
2 Read Pass-75%
3 Sing Fail-47%
3 Read Pass-55%
4 Write Pass-90%
4 Sing Fail-10%
The results need to be in the following format.
A row showing the student name, followed by rows of the students' results.
If a student does not have any results they will not be included.
1, abc, good, 1A
1, Read, Pass-67%
1, Write, Pass-89%
1, Sing, Pass-99%
2, xyz, bad, 1B
2, Read, Pass-75%
3, dsk, good, 1A
3, Sing, Fail-47%
3, Read, Pass-55%
4, uij, bad, 1B
4, Write, Pass-90%
4, Sing, Fail-10%
I attempted using Union to no avail, it is similar to a pivot have not had any luck with that either. Is assume i’m missing a trick here, how can I get this done?
I have included the data if it makes it any easier!
CREATE TABLE RESULTS (ID Int, Lesson varchar(12), Result nvarchar(8))
insert into RESULTS (ID, Lesson, Result)
values
(1,'Read', 'Pass-67%'),
(1,'Write', 'Pass-89%'),
(1,'Sing', 'Pass-99%'),
(2,'Read', 'Pass-75%'),
(3,'Sing', 'Fail-47%'),
(3,'Read','Pass-55%'),
(4,'Write', 'Pass-90%'),
(4,'Sing', 'Fail-10%')
CREATE TABLE STUDENTS (ID int, Name varchar(5), Attendance nvarchar(10),
Class nvarchar (3))
insert into STUDENTS values
(1,'abc','good','1A'),
(2,'xyz','bad','1B'),
(3,'dsk','good','1A'),
(4,'uij','bad','1B'),
(5,'sss','bad','1A'),
(6,'fff','good','1D'),
(7,'ccc','good','1A')
You can use a UNION with a few workarounds.
;WITH Data AS
(
SELECT
S.ID,
S.Name,
S.Attendance,
S.Class,
IsStudent = 1
FROM
Students AS S
WHERE
EXISTS (SELECT 'at least one result' FROM Results AS R WHERE R.ID = S.ID)
UNION ALL
SELECT
ID = R.ID,
Name = R.Lesson,
Attendance = R.Result,
Class = NULL,
IsStudent = 0
FROM
Results AS R
)
SELECT
D.ID,
D.Name,
D.Attendance,
D.Class
FROM
Data AS D
ORDER BY
ID,
IsStudent DESC
But, as you can see on the final column names, you are mixing different data together which is not a good thing to do.
Use union all :
select t.*
from(select ID, Name, Attendance, class
from STUDENTS s
where exists (select 1 from RESULTS where id = s.id) union all
select ID, Lesson, Result, null
from RESULTS r
) t
order by id, (case when class is not null then 0 else 1 end);
Simply concat those columns and Union
SELECT CONVERT(VARCHAR(10),id)+' , '+Name+' , '+Attendance
AS ResultSet INTO #T FROM dbo.STUDENTS
UNION ALL
SELECT CONVERT(VARCHAR(10),ID)+' , '+Lesson+' , '+ Result
FROM dbo.RESULTS
SELECT * FROM #T ORDER BY ResultSet
DROP TABLE #T

Compare number column with String in Oracle

I have couple of columns in Oracle Table.
EMP_SEQ_NO Number(5)
Some_COL Varchar(20)
EMP_SEQ_NO Some_COL
10 ABCD
11 11
12 Test
13 Tommy
14 14
15 15
16 Ronny
I am trying to do something like
Select * from EMP where EMP_SEQ_NO=Some_COL
It is throwing Invalid number error.
Please help
Using to_char solves your problem.
Select * from EMP where to_char(EMP_SEQ_NO)= to_char(Some_COL)
Both of them are of different types. So, you should cast one of them to the type of the other:
Select * from EMP
where CAST(EMP_SEQ_NO as varchar(20)) = Some_COL
OR
Select * from EMP
where EMP_SEQ_NO = CAST(Some_COL as number(5))
to_number will solve this
Select * from EMP where EMP_SEQ_NO= to_number(Some_COL, '99999');

How to write IN clause query to replace null for no value parameter

I am writing a query in which where clause have IN clause and there are large number of values in this IN clause , I want to fetch the result such that if there is no value exist in table for value given in IN clause then a raw containing 0 or null should return for that value. for example..
select age,sex,date_joining from emp where name IN ('amit','john','paul','dilip')
Now assume for this query ,data for john and paul does not exist in database then result should be like below..
21 male 21-AUG-2011
null null null
null null null
25 male 9-aug-2010
we can also have 0 instead of null if null is not possible
Thanks...
select filter.name
, emp.age
, emp.sex
, emp.date_joining
from (
values ('amit'), ('john'), ('paul'), ('dilip')
) filter(name)
left join
emp
on emp.name = filter.name
Live example at SQL Fiddle.
For older values of SQL Server, replace the line with values by:
from (
select 'amit'
union all select 'john'
union all select 'paul'
union all select 'dilip'
) filter(name)
You can also use common table expression to get this result:
;With AllEmpDetails as
(
Select [Name] from emp
UNION Select 'amit'
UNION Select 'john'
UNION Select 'paul'
UNION Select 'dilip'
)Select AllEmpDetails.Name, e2.Age, e2.Sex, e2.date_joining
from AllEmpDetails
Left Join emp e2 on e2.[Name] = AllEmpDetails.Name
In my database, I have already added details for amit and dilip so i have used UNION since you can easily get the detail about the available employees. On the other hand you can use UNION ALL with Distinct.