How to avoid order by in group by query result [duplicate] - sql

I am trying to display the records,order as in the where clause..
example:
select name from table where name in ('Yaksha','Arun','Naveen');
It displays Arun,Naveen,Yaksha (alphabetical order)
I want display it as same order i.e 'Yaksha''Arun','Naveen'
how to display this...
I am using oracle db.

Add this ORDER BY at the query's end:
order by case name when 'Yaksha' then 1
when 'Arun' then 2
when 'Naveen' then 3
end
(There's no other way to get that order. You need an ORDER BY to get a specific result set order.)

It may be a bit clunky, but you can create a custom ordering with a case expression:
SELECT *
FROM my_table
WHERE name IN ('Yaksha', 'Arun','Naveen')
ORDER BY CASE name WHEN 'Yaksha' THEN 1
WHEN 'Arun' THEN 2
WHEN 'Naveen' THEN 3
END ASC
A slightly longer option, but one that prevents duplication of the string literals is to use a subquery:
SELECT m.*
FROM my_table m
JOIN (SELECT 'Yaksha' AS name, 1 AS name_order FROM dual
UNION ALL
SELECT 'Arun' AS name, 2 AS name_order FROM dual
UNION ALL
SELECT 'Naveen' AS name, 3 AS name_order FROM dual) o
ON o.name = m.name
ORDER BY o.name_order ASC

You can try with something like the following:
SELECT *
FROM test
WHERE name IN ( 'Yaksha', 'Arun', 'Naveen' )
ORDER BY instr ( q'['Yaksha', 'Arun', 'Naveen']', name ) ASC
This way could be useful if your IN list is somehow dynamic.

If the list of values is dynamic or you just don't want to repeat the values you could use (or abuse, depending on your point of view) a table collection, and join your real table to a table collection expression instead of using IN:
select your_table.name
from table(sys.odcivarchar2list('Yaksha','Arun','Naveen')) t
join your_table on your_table.name = t.column_value;
Which will generally work, but of course without an order-by clause is not guaranteed to work, so you can use an inline view to assign the order:
select your_table.name from (
select row_number() over (order by null) as rn, column_value as name
from table(sys.odcivarchar2list('Yaksha','Arun','Naveen'))
) t
join your_table on your_table.name = t.name
order by t.rn;
This still relies on row_number() over (order by null) using the order of the elements in the collection; which relies on collection unnesting preserving the element order. I don't think that's guaranteed either, so there is still some risk involved.

Related

How to replace IN CLAUSE USING EXISTS?

select
TV.ATTRIBUTE
FROM
TABLE_VALUE TV
WHERE
TV.NUMBERS IN (SELECT MAX(TV1.NUMBERS) FROM TABLE_VALUE TV1
WHERE TV.UNIQUE_ID=TV1.UNIQUE_ID GROUP BY UNIQUE_ID )
I'm not sure exists would help here, because - as you put it - for each unique_id there be many numbers values, and you want to select attribute for highest numbers for that particular unique_id.
exists is useful when you want to check whether something ... well, exists, but that's not the case here.
You do not want EXISTS, instead you can use the RANK or DENSE_RANK analytic functions:
SELECT attribute
FROM (
SELECT attribute,
DENSE_RANK() OVER (PARTITION BY unique_id ORDER BY numbers DESC) AS rnk
FROM table_value
)
WHERE rnk = 1
or use the MAX analytic function:
SELECT attribute
FROM (
SELECT attribute,
numbers,
MAX(numbers) OVER (PARTITION BY unique_id) AS max_numbers
FROM table_value
)
WHERE numbers = max_numbers;
Either option will only read from the table once.
If you really did want to use EXISTS (or IN) then it will be less efficient as you will query the same table twice but you can do it with a HAVING clause:
SELECT tv.attribute
FROM table_value tv
WHERE EXISTS(
SELECT 1
FROM table_value tv1
WHERE tv1.unique_id = tv.unique_id
HAVING MAX(tv1.numbers) = tv.numbers
)
fiddle

Is it possible to UNION distinct rows but disregard one column to determine uniqueness?

select d.id, d.registration_number
from DOCUMENTS d
union
select dd.id, dd.registration_number
from DIFFERENT_DOCUMENTS dd
Would it be possible to union those results based solely on the uniqueness of the registration_number, disregarding the id of the documents?
Or, is it possible to achieve the same result in a different way?
Just to add: actually I'm unioning 5 queries, each ~20 lines long, with 4 columns that should be disregarded in determining uniqueness.
you basically need to wrap the unioned data with something else to get only the ones you want.
SELECT min(id), registration_number
FROM (SELECT id, registration_number
FROM documents
UNION ALL
SELECT id, registration_number
FROM different_documents)
GROUP BY registration_number
Union will check the combination of all the columns for uniqueness. You could, however, use union all (that does not remove duplicates) and then apply the logic yourself using the row_number window function:
SELECT id, registration_number
FROM (SELECT id, registration_number,
ROW_NUMBER() OVER (PARTITION BY registration_number ORDER BY id) AS rn
FROM (SELECT id, registration_number
FROM documents
UNION ALL
SELECT id, registration_number
FROM different_documents) u
) r
WHERE rn = 1
Since the other answers are already correct, may I ask why do you need to retrieve other columns in that query since the primary purpose appear to gather unique registration numbers?
Wouldn't it be simpler to first gather unique registration number and then retrieve the other info?
Or in your actual query, first gather the info without the columns that should be disregarded and then gather the info in these column if need be?
Like,for example, making a view with
SELECT d.registration_number
FROM DOCUMENT d
UNION
SELECT dd.registration_number
FROM DIFFERENT_DOCUMENT dd
and then gather information using that view and JOINS?
Assuming registration_number is unique in each table, you can use not exists:
select d.id, d.registration_number
from DOCUMENTS d
union all
select dd.id, dd.registration_number
from DIFFERENT_DOCUMENTS dd
where not exists (select 1
from DOCUMENTS d
where dd.registration_number = d.registration_number
);

How can I make a distinct with multiple field

I have some duplicate mail in my database but I can't remove it.
I want Select some field but without duplicate mail.
I have a request like this :
SELECT
DISTINCT MAIL,
ID,
CIVILITE,
PRENOM,
NAME
FROM CONTACT WHERE CODE_PAYS = 'DE'
When I launch this request, my duplicate values on mail are already here.
Do you know how can I do that ?
Update: i have tried this approach but i need to use it in a view:
ALTER VIEW ALL_VW_CONTACT_DE WITH SCHEMABINDING
AS
with cte as
(
select rn = row_number() over (partition by c.Mail Order By c.Id asc), c.Mail, c.Id, c.Civilite, c.Prenom, c.Name
from dbo.CONTACT c
where code_pays = 'DE'
)
select Mail, Id, Civilite, Prenom, Name
from cte
where rn = 1
But this doesn't work, i get this error:
Cannot schema bind view 'MY_TABLE' because name 'CONTACT' is invalid
for schema binding. Name must be in two-part format and an object
cannot reference itself
When I launch this request, my duplicate values on mail are already
here.
The reason for it is that DISTINCT doesn't work like you think. It doesn't look only at the first column after the DISTINCT keyword but it compares all columns in the list. So just if all are equal it is considered a duplicate.
One easy way is using ROW_NUMBER:
with cte as
(
select rn = row_number() over (partition by c.Mail Order By c.Id asc), c.*
from dbo.Contact c
where Code_Pays = 'DE'
)
select Mail, Id, Civilite, Prenom, Name
from cte
where rn = 1
Change the order by if you want to take a different record, here i take the one with min-ID.
you can use row_number as below
Select top (1) with ties * from Contact
where CODE_PAYS = 'DE'
order by row_number() over(partition by mail order by id)
When you use DISTINCT with other fields, then you get only original combinations of these fields.
For this case, you should exclude all dynamic fields from query (possibly ID):
SELECT
DISTINCT MAIL,
CIVILITE,
PRENOM,
NAME
FROM CONTACT WHERE CODE_PAYS = 'DE'
The problem here is probably The ID field. Since it should be unique for each row, you can't group the other fields. Remove it from the query and you should be fine.
When you do a distinct query, the trick is to look at the results and finding what columns are returning different values, that's what's differentiating them. If you add the results in your question we can help you further.

How to display records from a table ordered as in the where clause?

I am trying to display the records,order as in the where clause..
example:
select name from table where name in ('Yaksha','Arun','Naveen');
It displays Arun,Naveen,Yaksha (alphabetical order)
I want display it as same order i.e 'Yaksha''Arun','Naveen'
how to display this...
I am using oracle db.
Add this ORDER BY at the query's end:
order by case name when 'Yaksha' then 1
when 'Arun' then 2
when 'Naveen' then 3
end
(There's no other way to get that order. You need an ORDER BY to get a specific result set order.)
It may be a bit clunky, but you can create a custom ordering with a case expression:
SELECT *
FROM my_table
WHERE name IN ('Yaksha', 'Arun','Naveen')
ORDER BY CASE name WHEN 'Yaksha' THEN 1
WHEN 'Arun' THEN 2
WHEN 'Naveen' THEN 3
END ASC
A slightly longer option, but one that prevents duplication of the string literals is to use a subquery:
SELECT m.*
FROM my_table m
JOIN (SELECT 'Yaksha' AS name, 1 AS name_order FROM dual
UNION ALL
SELECT 'Arun' AS name, 2 AS name_order FROM dual
UNION ALL
SELECT 'Naveen' AS name, 3 AS name_order FROM dual) o
ON o.name = m.name
ORDER BY o.name_order ASC
You can try with something like the following:
SELECT *
FROM test
WHERE name IN ( 'Yaksha', 'Arun', 'Naveen' )
ORDER BY instr ( q'['Yaksha', 'Arun', 'Naveen']', name ) ASC
This way could be useful if your IN list is somehow dynamic.
If the list of values is dynamic or you just don't want to repeat the values you could use (or abuse, depending on your point of view) a table collection, and join your real table to a table collection expression instead of using IN:
select your_table.name
from table(sys.odcivarchar2list('Yaksha','Arun','Naveen')) t
join your_table on your_table.name = t.column_value;
Which will generally work, but of course without an order-by clause is not guaranteed to work, so you can use an inline view to assign the order:
select your_table.name from (
select row_number() over (order by null) as rn, column_value as name
from table(sys.odcivarchar2list('Yaksha','Arun','Naveen'))
) t
join your_table on your_table.name = t.name
order by t.rn;
This still relies on row_number() over (order by null) using the order of the elements in the collection; which relies on collection unnesting preserving the element order. I don't think that's guaranteed either, so there is still some risk involved.

SQL Server : UNION ALL but remove duplicate IDs by choosing first date of occurrence

I am unioning two queries but I'm getting an ID that occurs in each query. I do not know how to keep only the first time the id occurs. Everything else about the row is different. In general, it will be hard to know which of the two queries I will have to keep a duplicate on, therefore, I need a general solution.
I was thinking about creating a temp table and choosing the min date (once the date has been converted to an int).
Any ideas on the proper syntax?
You can do this using the row_number() function. This will assign a sequential number, starting with 1, to each row with the same id (based on the partition by clause). The ordering of the sequence is determined by the order by clause. So, the following assigns 1 to the earliest date for each id:
select t.*
from (select t.*,
row_number() over (partition by id order by date asc) as seqnum
from ((select *
from <subquery1>
) union all
(select *
from <subquery2>
)
) t
) t
where seqnum = 1;
The final where clause simply filters for the first occurrence.
If you use the keyword UNION, then it will remove duplicates from the two data sets you are working with. UNION ALL preserves duplicates.
You can view the specifics here:
http://www.w3schools.com/sql/sql_union.asp
If you want to only have one of the 2 records and they are not identical you will have to filter them yourself. You may need to do something like the following. THis may be possible to do with the one (select union select) block but this should get you started.
select *
from (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x1
, (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x2
where x1.id = x2.id
and x1.date < x2.date
Although rethinking this if you go down a path like this why bother to UNION it?