Distinct with where condition - sql

I have table as below:
I want to perform distinct on city but if city is duplicate then return row which having maximum ref_id. Result should contains all the columns.

Test data:
DECLARE #t_temp TABLE (ID smallint,
name varchar(10),
city varchar(10),
ref_id smallint);
INSERT INTO #t_temp
VALUES
(1, 'xyz', 'a', 101),
(2, 'pqr', 'a', 102),
(3, 'ijk', 'a', 103),
(4, 'abc', 'b', 104),
(5, 'ahg', 'c', 10);
Actual query:
SELECT ID
, name
, city
, ref_id
FROM (SELECT *
, ROW_NUMBER() OVER (PARTITION BY city ORDER BY ref_id DESC) Ranking
FROM #t_temp) base
WHERE Ranking = 1;
Result:
ID name city ref_id
------ ---------- ---------- ------
3 ijk a 103
4 abc b 104
5 ahg c 10
Basicly, what I'm doing is assigning a 'ranking' to all your records grouped by city and ordered by ref_id, and then retaining only the "number one" record. This is an alternative to what Rahul proposed, which is also a valid solution to your problem. The only difference between the two is that in Rahul's example he'll return multiple records if multiple exist with the same city and ref_id (considering it being the highest one), where the solution above will only return a single record. To reach the same behavior as Rahul, you can change the ROW_NUMBER() to RANK() or DENSE_RANK().

Try this:
Select tb1.* from Table1 as tb1
inner join (
Select city, Max(ref_id) as 'ref_id' from Table1 group by city
) as tb2
on tb1.city = tb2.city and tb1.ref_id = tb2.ref_id

Related

Union two queries ordered by newid

I have a table that stores employees (id, name, and gender). I need to randomly get two men and two women.
CREATE TABLE employees
(
id INT,
name VARCHAR (10),
gender VARCHAR (1),
);
INSERT INTO employees VALUES (1, 'Mary', 'F');
INSERT INTO employees VALUES (2, 'Jake', 'M');
INSERT INTO employees VALUES (3, 'Ryan', 'M');
INSERT INTO employees VALUES (4, 'Lola', 'F');
INSERT INTO employees VALUES (5, 'Dina', 'F');
INSERT INTO employees VALUES (6, 'Paul', 'M');
INSERT INTO employees VALUES (7, 'Tina', 'F');
INSERT INTO employees VALUES (8, 'John', 'M');
My attempt is the following:
SELECT TOP 2 *
FROM employees
WHERE gender = 'F'
ORDER BY NEWID()
UNION
SELECT TOP 2 *
FROM employees
WHERE gender = 'M'
ORDER BY NEWID()
But it doesn't work since I can't put two order by in the same query.
Why not just use row_number()? One method without a subquery is:
SELECT TOP (4) WITH TIES e.*
FROM employees
WHERE gender IN ('M', 'F')
ORDER BY ROW_NUMBER() OVER (PARTITION BY gender ORDER BY newid());
This is slightly less performant than using ROW_NUMBER() in a subquery.
Or, a fun method would use APPLY:
select e.*
from (values ('M'), ('F')) v(gender) cross apply
(select top (2) e.*
from employees e
where e.gender = v.gender
order by newid()
) e;
You cannot put an ORDER BY in the combinable query (the first one) of the UNION. However, you can use ORDER BY if you convert each one into a table expression.
For example:
select *
from (
SELECT TOP 2 *
FROM employees
WHERE gender = 'F'
ORDER BY newid()
) x
UNION ALL
select *
from (
SELECT TOP 2 *
FROM employees
WHERE gender = 'M'
ORDER BY newid()
) y
Result:
id name gender
--- ----- ------
5 Dina F
4 Lola F
2 Jake M
3 Ryan M
See running example at SQL Fiddle.

How to get unique records from 3 tables

I have 3 tables and I am trying to get unique results from all 3 tables (including other columns from each table).
I have tried union approach but that approach only works when I have single column selected from each table.
As soon as I want another corresponding column value from each table, I don't get unique values for the field I am trying to get.
Sample Database and query available here as well: http://www.sqlfiddle.com/#!18/1b9a6/10
Here is the example tables i have created.
CREATE TABLE TABLEA
(
id int,
city varchar(6)
);
INSERT INTO TABLEA ([id], [city])
VALUES
(1, 'A'),
(2, 'B'),
(3, 'C');
CREATE TABLE TABLEB
(
id int,
city varchar(6)
);
INSERT INTO TABLEB ([id], [city])
VALUES
(1, 'B'),
(2, 'C'),
(3, 'D');
CREATE TABLE TABLEC
(
id int,
city varchar(6)
);
INSERT INTO TABLEC ([id], [city])
VALUES
(1, 'C'),
(2, 'D'),
(2, 'E');
Desired result:
A,B,C,D,E
Unique city from all 3 table combined. By unique, I am referring to DISTINCT city from the combination of all 3 tables. Yes, the id is different for common values between tables but it doesn't matter in my use-case if id is coming from table A, B OR C, as long as I am getting DISTINCT (aka UNIQUE) city across all 3 tables.
I tried this query but no luck (city B is missing in the output):
SELECT city, id
FROM
(SELECT city, id
FROM TABLEA
WHERE city NOT IN (SELECT city FROM TABLEB
UNION
SELECT city FROM TABLEC)
UNION
SELECT city, id
FROM TABLEB
WHERE city NOT IN (SELECT city FROM TABLEA
UNION
SELECT city FROM TABLEC)
UNION
SELECT city, id
FROM TABLEC) AS mytable
try this. As this should give you distinct city with there first appear id:
select distinct min(id) over(partition by city) id, city from (
select * from TABLEA
union all
select * from TABLEB
union all
select * from TABLEC ) uni
You got the right idea, just wrap the UNION results in a subquery/temp table and then apply the DISTINCT
WITH TABLEE AS (
SELECT city, id FROM TABLEA
UNION
SELECT city, id FROM TABLEB
UNION
SELECT city, id FROM TABLEC
)
SELECT DISTINCT city
FROM TABLEE

select add sum below each group using select query

Sample Table :
INSERT INTO Table1
([ID], [Name])
VALUES
('1', 'Alpha'),
('2', 'Beta'),
('3', 'Beta'),
('4', 'Beta'),
('5', 'Charlie'),
('6', 'Charlie')
Using a select query, I want to add a row with the sum of id per name below every group. I've tried using union but I would need to do a select query per name. Names could change anytime though.
Select query result :
ID Name
1 Alpha
1
2 Beta
3 Beta
4 Beta
9
5 Charlie
6 Charlie
11
You can achieve this with a union having a computed column to keep track of the source name on each side of the union:
SELECT ID, Name
FROM
(
SELECT ID, Name AS position, Name FROM Table1
UNION ALL
SELECT SUM(ID), Name, NULL
FROM Table1
GROUP BY Name
) t
ORDER BY
position, ID;
Demo
SELECT SUM(Id), Name from Table1 GROUP BY name
Try this to get addition of Id field and group by Name.

Oracle SQL - IN Clause display all record given in IN condition even when data not present in table

I have a table customer as described below.
customer_id number
customer_name varchar(30)
city varchar(20)
columns. When the below query run in Oracle db
SELECT customer_id, city FROM customer WHERE city IN ('abc', 'def', 'ghi')
I'm getting the output as shown below. Table doesn't have record for ghi
customer_id, city
1, abc
2, def
I'm trying to form the output something as below.
customer_id, city
1, abc
2, def
null, ghi
Though no record for ghi in table, want to display it in SELECT query output with rest of the column value as null.
Much appreciate help in writing sql for this scenario.
You need a derived table containing all possibilities. Either you have one, like a city table and then you can do:
SELECT t.customer_id,s.city
FROM city_table s
LEFT JOIN customer t
ON(s.id = t.city)
WHERE s.city IN ('abc', 'def', 'ghi')
Or generate the values your self:
SELECT t.customer_id,s.city
FROM (SELECT 'abc' as id FROM DUAL
UNION ALL
SELECT 'def' FROM DUAL
UNION ALL
SELECT 'ghi' FROM DUAL) s
LEFT JOIN customer t
ON(s.id = t.city)
WHERE s.id IN('abc', 'def', 'ghi')

SQL Server Distinct Question

I need to be able to select only the first row for each name that has the greatest value.
I have a table with the following:
id name value
0 JOHN 123
1 STEVE 125
2 JOHN 127
3 JOHN 126
So I am looking to return:
id name value
1 STEVE 125
2 JOHN 127
Any idea on the MSSQL Syntax on how to perform this operation?
While you specified SQL Server, you did not specify the version. If you are using SQL Server 2005 or later, you can do something like:
With RankedItems As
(
Select id, name, value
, Row_Number() Over ( Partition By name Order By value Desc, id Asc ) As ItemRank
From Table
)
Select id, name, value
From RankedItems
Where ItemRank = 1
try:
SELECT
MIN(id) as id,dt.name,dt.value
FROM (SELECT
name,MAX(value) as value
FROM YourTable
GROUP BY name
) dt
INNER JOIN YourTable t ON dt.name=t.name and dt.value=t.value
GROUP BY dt.name,dt.value
try it out:
DECLARE #YourTable table (id int, name varchar(10), value int)
INSERT #YourTable VALUES (0, 'JOHN', 123)
INSERT #YourTable VALUES (1, 'STEVE', 125)
INSERT #YourTable VALUES (2, 'JOHN', 127)
INSERT #YourTable VALUES (3, 'JOHN', 126)
--extra data not in the question, shows why you need the outer group by
INSERT #YourTable VALUES (4, 'JOHN', 127)
INSERT #YourTable VALUES (5, 'JOHN', 127)
INSERT #YourTable VALUES (6, 'JOHN', 127)
INSERT #YourTable VALUES (7, 'JOHN', 127)
SELECT
MIN(id) as id,dt.name,dt.value
FROM (SELECT
name,MAX(value) as value
FROM #YourTable
GROUP BY name
) dt
INNER JOIN #YourTable t ON dt.name=t.name and dt.value=t.value
GROUP BY dt.name,dt.value
ORDER BY id
output:
id name value
----------- ---------- -----------
1 STEVE 125
2 JOHN 127
(2 row(s) affected)
You could do something like
SELECT id, name, value
FROM (SELECT id, name, value
ROWNUMBER() OVER (PARTITION BY name ORDER BY value DESC) AS r
FROM table) AS x
WHERE x.r = 1 ;
This will not work in SQL Server 2000 and earlier, but it will be incredibly fast in SQL Server 2005 and 2008
How about:
SELECT a.id, a.name, b.maxvalue
FROM mytbl a
INNER JOIN (SELECT id, max(value) as maxvalue
FROM mytbl
GROUP BY id) b ON b.id = a.id
SELECT a.id, a.name, a.value
FROM mytbl a
INNER JOIN (SELECT name, max(value) as maxvalue
FROM mytbl
GROUP BY name) b ON b.name = a.name and b.maxvalue = a.value