select add sum below each group using select query - sql

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.

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 select a record which have all id's in SQL?

I want select record which have all id's.
Example:
Name
ID
Ram
3
Ajay
1
Mogan
3
Ram
1
Ram
2
Here Ram have all id's (1,2,3). So, I want result as Ram.
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 UNION ALL
SELECT'AJAY',3 UNION ALL
SELECT 'MOGAN',2 UNION ALL
SELECT 'KUMAR',3 UNION ALL
SELECT 'RAM',2 UNION ALL
SELECT 'JAYA',1 UNION ALL
SELECT 'KABIL',3 UNION ALL
SELECT 'RAM',3
)
SELECT C.NAME
FROM CTE AS C
GROUP BY C.NAME
HAVING COUNT(DISTINCT C.CODE)=(SELECT COUNT(DISTINCT CODE) FROM CTE )
As far as I know, this is called "relational division". You can try my query or look for another possible solution
Select * from table where upper(name) = 'RAM'
This query would bring back all the IDs for RAM alone
how about string agg.
CREATE TABLE MyTable (
ID int,
Name varchar(255),
);
Insert into MyTable(ID, Name) values (1, 'Ram');
Insert into MyTable(ID, Name) values (2, 'Ram');
Insert into MyTable(ID, Name) values (3, 'Ram');
Insert into MyTable(ID, Name) values (1, 'Ajay');
Insert into MyTable(ID, Name) values (1, 'Mogan');
select Name, string_agg(ID, ',') as Ids
from MyTable
group by Name;
result
Ajay 1
Mogan 1
Ram 1,2,3
see result here
http://sqlfiddle.com/#!18/923bf/4
With reference to the with clause used by #surgey above,
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 from dual UNION ALL
SELECT'AJAY',3 from dual UNION ALL
SELECT 'MOGAN',2 from dual UNION ALL
SELECT 'KUMAR',3 from dual UNION ALL
SELECT 'RAM',2 from dual UNION ALL
SELECT 'JAYA',1 from dual UNION ALL
SELECT 'KABIL',3 from dual UNION ALL
SELECT 'RAM',3 from dual
)
select name, code, rank() over(partition by name order by code) rank
from cte
this query, it will bring back everybody in the and group them by name. THis could be one possible solution other use tou can use an "IN" clause in your where as shown below
Select * from table where upper(name) in ('RAM','AJAY')
If are you using MySql this will solve your issue:
SELECT r1.name
FROM raws r1
LEFT JOIN raws r2 ON r1.id = r2.id AND r1.name = r2.name
WHERE r2.id IN (1, 2, 3)
GROUP by r1.name
HAVING count(r2.id) = 3; # count of numbers in IN (1, 2, 3)
And if you have identifier in your table use it for join instead
of r1.id = r2.id AND r1.name = r2.name

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

Finding some same values within each ID

I have this kind of data, with ID column identifying potential duplicates,
in this data same Id means it is a same customer, what I want to do is show that 456 account not required as it is covered under account 123, is there a way I can do that on SQL or tableau? I want to show all accounts like 456 within ID group.
with cte as (
select min(customer_account) as account, id --This query will get the first account for each ID
from table
group by ID
)
select customer_account, id --this will show, for each id, all the 'duplicated' customers
from table
where customer_account not in (select account from cte)
the result should be:
456 1
789 1
ID with just one customer ID won't appear
Write a SQL query that selects the minimum Customer value for each ID. Join that dataset back to the original table where the original table's Customer value is greater than the minimum for each corresponding ID. Here is a SQLFiddle example:
http://www.sqlfiddle.com/#!9/93296f/20
Here is the DDL used to recreate your question:
CREATE TABLE Table1
(`Id` int, `Customer_Account` int, `City` varchar(9));
INSERT INTO Table1
(`Id`, `Customer_Account`, `City`)
VALUES
(1, 123, 'London'),
(1, 123, 'Paris'),
(1, 456, 'Paris'),
(1, 456, 'Mumbai'),
(1, 123, 'Mumbai'),
(1, 789, 'Singapore');
Here is the DML used to show the duplicate Customer Accounts. Query 3 should give you the final results.
-- Query 1: Find the First Account for each Customer
select `Id`,
min(`Customer_Account`) as 'First Account by Customer'
from Table1 group by `Id`;
-- Query 2: Find the First Account for Each Customer by City
select `Id`,
min(`Customer_Account`) as 'First Account by City',
`City`
from Table1
group by `Id`, `City`;
-- Query 3: Find the Duplicate Customer Accounts by ID
select distinct
A.Id,
A.Customer_Account as 'Duplicate Account by Customer',
FirstAcctList.First_Account
from Table1 A
join (
select
`Id`,
min(`Customer_Account`) as 'First_Account'
from Table1 group by `Id`) as FirstAcctList
on FirstAcctList.First_Account <> A.Customer_Account;

Distinct with where condition

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