SQL ignore one field with DISTINCT but ORDER BY it - sql

I have two SQL SELECT with UNION DISTINCT, one with data from a new Database and one from an old Database so in each SELECT I have a field that describes from which Database the data came.
A simplified Example code:
SELECT username, name, lastname, 1 AS DB
From new_DB.users
UNION DISTINCT
SELECT username, name, lastname, 2 AS DB
From old_DB.users
ORDER BY db, lastname, name ASC
Data output looks like this:
username
name
lastname
DB
Fmuster
Fiona
Muster
1
kroos
Kim
Roos
1
Mmuster
Max
Muster
1
kroos
Kim
Roos
2
Ysoroli
Yelda
Soroli
2
My problem is:
That there is duplicated data in the output.
The data that shouldn't be in the output is the second kroos but I can't just remove the field DB because I have to show all results from new_DB(DB 1) at the top.
thx for your help
Kim

You can use NOT EXISTS to filter out duplicate rows coming from old_DB.users:
SELECT username, name, lastname, 1 AS DB
FROM new_DB.users
UNION
SELECT o.username, o.name, o.lastname, 2 AS DB
FROM old_DB.users o
WHERE NOT EXISTS (
SELECT 1
FROM new_DB.users n
WHERE (n.username, n.name, n.lastname) = (o.username, o.name, o.lastname)
)
ORDER BY db, lastname, name ASC;
Or, with aggregation:
SELECT username, name, lastname, MIN(DB) AS DB
FROM (
SELECT username, name, lastname, 1 AS DB
FROM new_DB.users
UNION
SELECT username, name, lastname, 2 AS DB
FROM old_DB.users
) t
GROUP BY username, name, lastname
ORDER BY db, lastname, name ASC;

Related

SQL Union Select for alternate data

I created an sql query with union select and here is the query to join the two columns into one.
(select top 10 FirstName from Users) union (select top 10 LastName from Users)
Here is the Result:
QUERY RESULT 1
And here is the original data for the result 1 of union select.
ORIGINAL DATA
So, here is my problem.
How do I select the data of each firstname and lastname with the same column but the first one is firstname and the second one is lastname. For example:
Tumbaga Temp - <FirstName>
Villamor - <LastName>
Jun - <FirstName>
Villamor - <LastName>
FN83 - <FirstName>
Lising Geron - <LastName>
So on and so fort.
I am new in sql query. Thanks for your help.
We add a common row_number() to both parts to essentially group them, then order by this and the name type to display in clusters of first/last pairs
select 'First' as thename,
Firstname,
row_number() over(order by firstname) rn
from Users
union all
select 'Last',
Lastname,
row_number() over(order by firstname)
from users
order by rn, thename
If you only want the 1st 10, then wrap this and add a clause
select *
from
(
select 'First' as thename,
Firstname,
row_number() over(order by firstname) rn
from Users
union all
select 'Last',
Lastname,
row_number() over(order by firstname)
from users
)
where rn <=10
order by rn, thename
No need to use union, As per your description You have two columns 'firstName' and 'lastName' in a table and you want both in a single column. Just try the following query-:
select FirstName+' '+LastName as FullName from Users
SQL Server
you can add a column to both queries with your favourite data to be selected.
(select top 10 FirstName, 'FirstName' as NameType from SysUser) union (select top 10 LastName, 'LastName' as NameType from SysUser)

SQL: select from same table and same column, just different counts

I have a table called names, and I want to select 2 names after being count(*) as uniq, and then another 2 names just from the entire sample pool.
firstname
John
John
Jessica
Mary
Jessica
John
David
Walter
So the first 2 names would select from a pool of John, Jessica, and Mary etc giving them equal chances of being selected, while the second 2 names will select from the entire pool, so obvious bias will be given to John and Jessica with multiple rows.
I'm sure there's a way to do this but I just can't figure it out. I want to do something like
SELECT uniq.firstname
FROM (SELECT firstname, count(*) as count from names GROUP BY firstname) uniq
limit 2
AND
SELECT firstname
FROM (SELECT firstname from names) limit 2
Is this possible? Appreciate any pointers.
I think you are close but you need some randomness for the sampling:
(SELECT uniq.firstname
FROM (SELECT firstname, count(*) as count from names GROUP BY firstname) uniq
ORDER BY rand()
limit 2
)
UNION ALL
(SELECT firstname
FROM from names
ORDER BY rand()
limit 2
)
As mentioned here you can use RAND or similar functions to achieve it depending on the database.
MySQL:
SELECT firstname
FROM (SELECT firstname, COUNT(*) as count FROM names GROUP BY firstname)
ORDER BY RAND()
LIMIT 2
PostgreSQL:
SELECT firstname
FROM (SELECT firstname, COUNT(*) as count FROM names GROUP BY firstname)
ORDER BY RANDOM()
LIMIT 2
Microsoft SQL Server:
SELECT TOP 2 firstname
FROM (SELECT firstname, COUNT(*) as count FROM names GROUP BY firstname)
ORDER BY NEWID()
IBM DB2:
SELECT firstname , RAND() as IDX
FROM (SELECT firstname, COUNT(*) as count FROM names GROUP BY firstname)
ORDER BY IDX FETCH FIRST 2 ROWS ONLY
Oracle:
SELECT firstname
FROM(SELECT firstname, COUNT(*) as count FROM names GROUP BY firstname ORDER BY dbms_random.value )
WHERE rownum in (1,2)
Follow the similar approach for selecting from entire pool

No column was specified for column 1 of 'T1' when using a sub-select with a group by

I have a working query:
SELECT
COUNT(*), ACCOUNT_ID
FROM
CDS_PLAYER
GROUP BY
ACCOUNT_ID
HAVING
COUNT(*) > 1`
Output
No column name Account_ID
----------------------------
'2' '12345'
I'm trying to add names to these accounts (all from the same table) but with no luck. The only query that gets me close is:
SELECT
LASTNAME, FIRSTNAME, COUNT(ACCOUNT_ID) AS NUMBER
FROM
(SELECT
COUNT(*), ACCOUNT_ID
FROM
CDS_PLAYER
GROUP BY
ACCOUNT_ID
HAVING
COUNT(*) > 1) AS T1
GROUP BY
LASTNAME, FIRSTNAME, PLAYER_ID
But I get an error:
No column was specified for column 1 of 'T1'
Like I said VERY NEW AT THIS. My boss of 4 months wanted me to learn and so I'm self taught (books and google). Any help at all to get me where I need to be would be appreciated!
(I'm using Windows Server 2003 and SQL Server 2000)
The error message can be resolved as below
SELECT LASTNAME, FIRSTNAME, COUNT(ACCOUNT_ID) AS NUMBER
FROM
(SELECT COUNT(*) AS Total, ACCOUNT_ID FROM CDS_PLAYER GROUP BY ACCOUNT_ID HAVING
COUNT(*) > 1) AS T1
GROUP BY LASTNAME, FIRSTNAME, PLAYER_ID`
Add as TOTAL after the count(*)
Does this do what you want?
SELECT COUNT(*), ACCOUNT_ID, LASTNAME, FIRSTNAME, PLAYER_ID
FROM CDS_PLAYER
GROUP BY ACCOUNT_ID, LASTNAME, FIRSTNAME, PLAYER_ID
HAVING COUNT(*) > 1;
You should also update your version of SQL Server. It is like 15 years out of date and hasn't been supported in many years. You can download a free version of SQL Server Express from Microsoft.
you want to select the LASTNAME and FIRSTNAME, but havn't it selected in your subselect. You only can access field which are in the resultset.
Solution: Add it to your GROUP BY clause.
ie:
SELECT
LASTNAME, FIRSTNAME, COUNT(ACCOUNT_ID) AS NUMBER
FROM
(SELECT COUNT(*), LASTNAME, FIRSTNAME, ACCOUNT_ID
FROM CDS_PLAYER
GROUP BY ACCOUNT_ID, LASTNAME, FIRSTNAME
HAVING COUNT(*) > 1) AS T1
GROUP BY
LASTNAME, FIRSTNAME, PLAYER_ID

In a SQL GROUP BY query, what value is used for the non-aggregate columns?

Say I've got the following data back from a SQL query:
Lastname Firstname Age
Anderson Jane 28
Anderson Lisa 22
Anderson Jack 37
If I want to know the age of the oldest person with the last name Anderson, I can select MAX(Age) and GROUP BY Lastname. But I also want to know the first name of that oldest person. How can I make sure that, when the Firstname values are collapsed into one row by the GROUP BY, I get the Firstname value from the same row where I got the max age?
For those RDBMS that support it (e.g., SQL Server 2005+), you can use a window function:
select t.Lastname, t.Firstname, t.Age
from (select Lastname, Firstname, Age,
row_number() over (partition by Lastname order by Age desc) as RowNum
from YourTable
) t
where t.RowNum = 1
For others, you'd need a subquery on Lastname and a join to get Firstname:
select yt.Lastname, yt.Firstname, yt.Age
from YourTable yt
inner join (select LastName, max(Age) as MaxAge
from YourTable
group by LastName) q
on yt.Lastname = q.Lastname
and yt.Age = q.MaxAge
You have to join back to the table from your grouped results - i.e. create a view or a nested query to contain the group by.
The main thing you need to watch out for whatever your approach is that there might be more than 1 firstname with the same age for a given lastname.
This query will return just 1 row, but if your data set had more than one 'Anderson' aged 37, it could return either one:
select firstname, age
from yourtable
where lastname = 'Anderson'
order by age desc limit 1

How we can use CTE in subquery in sql server?

How we can use a CTE in a subquery in SQL Server?
like:
SELECT id (I want to use CTE here), name FROM table_name
Just define your CTE on top and access it in the subquery?
WITH YourCTE(blubb) AS
(
SELECT 'Blubb'
)
SELECT id,
(SELECT blubb FROM YourCTE),
name
FROM table_name
It doesn't work:
select id (I want to use CTE here), name from table_name
It's not possible to use CTE in sub queries.
You can realize it as a work around:
CREATE VIEW MyCTEView AS ..here comes your CTE-Statement.
Then you are able to do this:
select id (select id from MyCTEView), name from table_name
Create a view with CTE/ Multiple CTEs with UNION sets of all CTEs
CREATE VIEW [dbo].[_vEmployees]
AS
WITH
TEST_CTE(EmployeeID, FirstName, LastName, City, Country)
AS (
SELECT EmployeeID, FirstName, LastName, City, Country FROM Employees WHERE EmployeeID = 4
),
TEST_CTE2
AS (
SELECT EmployeeID, FirstName, LastName, City, Country FROM Employees WHERE EmployeeID = 7
)
SELECT EmployeeID, FirstName, LastName, City, Country FROM TEST_CTE UNION SELECT * FROM TEST_CTE2
GO
Now, use it into sub query
SELECT * FROM Employees WHERE EmployeeID IN (SELECT EmployeeID FROM _vEmployees)