SQL: Select the same column twice in one query? - sql

I'm currently working on a query where I need to pull a list of items, as well as the date they were entered into the system and the name and user ID of the person who entered them.
My Items table contains the columns CreateDate, CreatedBy (this is the person's user ID), LastChanged (this is a date), and LastChangedBy (also a user ID, being as the person who entered the item isn't always the same person who created it).
I have the Items table joined with a User table so I can pull the first and last name of the users who match the CreatedBy and LastChangedBy user IDs. The way I have the query written now, I've concatenated the two fields so they end up displayed as "LastName, FirstName" in a single column. I also want to only pull results for a certain user, and this user just needs to be the last person who changed the item - it doesn't matter whether or not they created it.
My query looks something like this:
SELECT
i.ItemName, i.CreateDate,
(u.LastName + ', ' + u.FirstName) as [Created By Name],
i.CreatedBy, i.LastChanged,
(u.LastName + ', ' + u.FirstName) as [Last Changed By Name],
i.LastChangedBy
FROM
Items i
JOIN
Users u ON i.CreatedBy = u.UserID
WHERE
i.LastChangedBy = 0001;
My issue though is that since I have the exact same piece of code to pull the user's name both times, it's pulling the same name regardless of whether the user IDs are different in the CreatedBy and LastChangedBy columns. So I end up with results that look like this:
ItemName CreateDate Created By Name CreatedBy LastChanged Last Changed By Name LastChangedBy
Item A 12/01/2015 Smith, John 0001 12/03/2015 Smith, John 0001
Item B 12/02/2015 Smith, John 0001 12/04/2015 Smith, John 0001
Item C 12/02/2015 Doe, Jane 1002 12/05/2015 Doe, Jane 0001
So even though John Smith was the last person to change Item C, it's still displaying Jane Doe's name there because (I assume) the strings of code to display the user's name is the same in both instances and it's just pulling the same name both times.
Is there a way to pull the first and last names from the User table twice in the same query but make sure they correspond with the correct user IDs?

I think you are missing a join in your query:
SELECT i.ItemName, i.CreateDate,
(uc.LastName + ', ' + uc.FirstName) as [Created By Name],
i.CreatedBy, i.LastChanged,
(ucb.LastName + ', ' + ucb.FirstName) as [Last Changed By Name],
i.LastChangedBy
FROM Items i LEFT JOIN
Users uc
ON i.CreatedBy = uc.UserID LEFT JOIN
Users ucb
ON i.LastChangedBy = ucb.UserId
WHERE i.LastChangedBy = 0001;
You need to join twice to get both users.

Related

Concatenate query output

I have two tables one containing the details of the user and another containing the details of user's tasks. I need to return one row for each user containing the username and the task ids.
The query I have is as follows
select
w.user
, (select '; ' +taskid from tasks d where d.guid = w.guid FOR XML PATH(''))
from taskuser w
where w.type = 'pm0'
group by w.user, w.tid
The output I am getting is
username
TaskId
Frane
PM0-10003
Jordan
PM0-10004
Jordan
PM0-10005
Jordan
PM0-10006
What I want is
Username
TaskId
Frane
PM0-10003
Jordan
PM0-10004, PM0-10005, PM0-10006

When was “Checked” added and who added it - SQL

I'm beginning to study SQL queries and attempting to understand some more difficult ones. I have these 2 tables:
User
ID_user
Name
Tracking
ID_Track
Old_Value
New_Value
Date_Entered
ID_user
The data entry interface looks like this:
User Column Date Old Value New Value
David (assistant) Status 02/2022 Pending Processing
David (assistant) address 02/2022 Miami New York City
David (assistant) Type 02/2022 House Apartment
David(assistant) Size 02/2022 Small Big
Peter(QA) Size 06/2022 - Medium
Peter(QA) Status 06/2022 - Checked
I'm trying to figure out how to join User and Tracking tables in order to know when the word “Checked” was added and who added it.
know when the word Checked was added and who added it
You can filter the tracking table for the keyword, and then bring the user name with a join on the user table:
select t.*, u.name
from tracking t
inner join user u on u.id_user = t.id_user
where t.new_value = 'Checked'
You can add more conditions in the where clause if you need more filtering criteria.

How to only select rows that have not been soft deleted in a SQL Query?

I am trying to deduplicate my companies database of companies.
The database administrator left for a new position and has not been replaced.
So I as the IT support guy have been roped into babysitting it for the time being.
I am having trouble with this query in MS Access.
SELECT dbo_Companies.PostCode,
dbo_Companies.Phone,
dbo_Companies.CpyID,
dbo_Companies.Name,
dbo_Companies.Building,
dbo_Companies.Street,
dbo_Companies.City,
dbo_Companies.Deleted
FROM dbo_Companies
WHERE (((dbo_Companies.PostCode) In (SELECT [PostCode] FROM [dbo_Companies]
As Tmp GROUP BY [PostCode],[Phone]
HAVING Count(*)>=2 And [Phone] = [dbo_Companies].[Phone]))
AND ((dbo_Companies.Deleted)=False))
ORDER BY dbo_Companies.PostCode, dbo_Companies.Phone;
It works mostly, the problem I am having is that it searches for records in which there are more than 2 instances of a post code and phone number, which is what I want.
However I want it to not search through any soft deleted records, it does search for soft deleted records but then filters them out of the table it produces.
PostCode
Phone
CpyID
Name
Building
Street
City
Deleted
AB12 4AX
1224404407
132931
joe bloggs
example text
street 1
Aberdeen
FALSE
AB12 4AX
1224404407
99338
joe bloggs co
example text
street 1
Aberdeen
TRUE
So I end up with loads of records which fit the criteria but only because of soft deleted records.
Is there any way to make it only match records by postcode and phone that are non soft deleted records, rather then just filtering them out of the resulting table.
Thank you to anyone in advanced.
Running the query you suggested johey, I'm still encountering the same results. It outputs some records which fit my criteria and some single ones that don't.
PostCode
Phone
CpyID
Name
Building
Street
City
Deleted
BB4 4PW
01706223999
26855
DRIVER TRETT (Driver Group Plc)
Driver House 4 St Crispin Way
Haslingden
Rossendale
FALSE
BB4 4PW
01706223999
210016
Driver Trett
Driver House 4
4 St Crispin Way
Rossendale
FALSE
BB4 7PA
01706219444
131303
Jacobson Group
Rossendale
FALSE
Jacobson Group should not be showing because the only record which matches on postcode and phone number has been soft deleted as shown below.
PostCode
Phone
CpyID
Name
Building
Street
City
Deleted
BB4 7PA
01706219444
85544
JACOBSON D& SONS LTD
Bacop Road
Rossendale
True
Okay, then try this one:
SELECT dbo_Companies.PostCode,
C.Phone,
C.CpyID,
C.Name,
C.Building,
C.Street,
C.City,
C.Deleted
FROM dbo_Companies AS C
WHERE C.PostCode In (
SELECT PostCode
FROM [dbo_Companies] As CTMP
WHERE CTMP.Phone = C.Phone
AND CTMP.Deleted=False
GROUP BY CTMP.PostCode, CTMP.Phone
HAVING Count(*)>=2
)
AND C.Deleted=False
ORDER BY C.PostCode, C.Phone;
However, the logic of that PostCode condition doesn't make sense to me. What are you trying to achieve with that?
Why does it filter companies based on the post code count? And why is the Phone relevant in that condition?

SQL Server: how to update rows with additional information

I have a situation in which a table has information like:
First Name | Last Name | Email
-----------+-----------+-----------------
John Doe jd#email.com
Jane Dont jnd#email.com
And I have a user who wants their email added on to both row's emails to looks like:
First Name | Last Name | Email
-----------+-----------+-----------------------------
John Doe jd#email.com;a#email.com
Jane Dont jnd#email.com;a#email.com
Thank you in advance for any help.
To add a#email.com to all rows in your table:
UPDATE Table
SET Email = Email + ';a#email.com'
To update certain rows:
UPDATE t
SET t.Email = t.Email + ';a#email.com'
FROM Table t
WHERE t.FirstName = 'John'
Note: the above query will update all records with the first name of John
Edit ******** Per #destination-data comment:
If you are also trying to add the new email to columns that have NULL value
SET Email = ISNULL(Email, '') + ';a#email.com'
"...Because null plus anything is null." This technique will change the value from NULL to an empty string plus the new value.

Querying for swapped columns in SQL database

We've had a few cases of people entering in first names where last names should be and vice versa. So I'm trying to come up with a SQL search to match the swapped columns. For example, someone may have entered the record as first_name = Smith, last_name = John by accident. Later, another person may see that John Smith is not in the database and enter a new user as first_name = John, last_name = Smith, when in fact it is the same person.
I used this query to help narrow my search:
SELECT person_id, first_name, last_name
FROM people
WHERE first_name IN (
SELECT last_name FROM people
) AND last_name IN (
SELECT first_name FROM people
);
But if we have people named John Allen, Allen Smith, and Smith John, they would all be returned even though none of those are actually duplicates. In this case, it's actually good enough that I can see the duplicates in my particular data set, but I'm wondering if there's a more precise way to do this.
I would do a self join like this:
SELECT p1.person_id, p1.first_name, p1.last_name
FROM people p1
join people p2 on p1.first_name = p2.last_name and p1.last_name = p2.first_name
To also find typos on names I recommend this:
SELECT p1.person_id, p1.first_name, p1.last_name
FROM people p1
join people p2 on soundex(p1.first_name) = soundex(p2.last_name) and
soundex(p1.last_name) = soundex(p2.first_name)
soundex is a neat function that "hashes" words in a way that two words that sound the same get the same hash. This means Anne and Ann will have the same soundex. So if you had an Anne Smith and a Smith Ann the query above would find them as a match.
Interesting. This is a problem that I cover in Data Analysis Using SQL and Excel (note: I only very rarely mention books in my answers or comments).
The idea is to summarize the data to get a likelihood of a mismatch. So, look at the number of times a name appears as a first name and as a last name and then combine these. So:
with names as (
select first_name as name, 1.0 as isf, 0.0 as isl
from people
union all
select last_name, 0, 1
from people
),
nl as (
select name, sum(isf) as numf, sum(isl) as numl,
avg(isf) as p_f, avg(isl) as p_l
from names
group by name
)
select p.*
from people p join
nl nlf
on p.first_name = nlf.name join
nl nll
on p.last_name = nll.name
order by (coalesce(nlf.p_l, 0) + coalesce(nll.p_f, 0));
This orders the records by a measure of mismatch of the names -- the sum of the probabilities of the first name used by a last name and a last name used as a first name.