Using SQL Server, I have a Contact table that contains the name and address of my contacts. I have several instances of multiple contacts living at the same address. When sending my newsletter, I only want to send it to each address one time. How can I modify the query below to only display the first contact at each address?
SELECT
dbo_Contact.Contact_Title AS Title,
dbo_Contact.Contact_FirstName AS [First Name],
dbo_Contact.Contact_LastName AS [Last Name],
dbo_Contact.Contact_Suffix AS Suffix,
dbo_Contact.Business_Name AS [Business Name],
dbo_Contact.Contact_Address1 AS [Address 1],
dbo_Contact.Contact_Address2 AS [Address 2],
dbo_Contact.Contact_City AS City,
dbo_Contact.Contact_State AS State,
dbo_Contact.Contact_Zip AS Zip,
dbo_Contact.Contact_Email AS Email
FROM
dbo_Contact
INNER JOIN
dbo_Mailing_Subscribers ON dbo_Contact.[ContactID] = dbo_Mailing_Subscribers.[ContactID]
WHERE
(((dbo_Contact.Contact_Inactive) = False)
AND ((dbo_Mailing_Subscribers.Mailing_ID) = True)
AND ((dbo_Mailing_Subscribers.Subscribed) = True));
For example, if Kurt and William live at 123 A Street and Steve lives at 123 B Avenue, I would only want to return records for Kurt and Steve.
Okay, here is my solution.
1 - Use table aliases to reduce code foot print.
2 - Changed true/false to 1/0 to meet TSQL Boolean values.
3 - Create RowNum partition by address1, address2, zip code order by last name, first name.
4 - Select only one row from the duplicates.
;
with cteData as
(
SELECT
C.Contact_Title AS Title,
C.Contact_FirstName AS [First Name],
C.Contact_LastName AS [Last Name],
C.Contact_Suffix AS Suffix,
C.Business_Name AS [Business Name],
C.Contact_Address1 AS [Address 1],
C.Contact_Address2 AS [Address 2],
C.Contact_City AS City,
C.Contact_State AS State,
C.Contact_Zip AS Zip,
C.Contact_Email AS Email,
row_number() over (partition by Contact_Address1, Contact_Address2, Contact_Zip
order by Contact_LastName, Contact_FirstName) as RowNum
FROM
dbo_Contact as C
INNER JOIN
dbo_Mailing_Subscribers as S
ON C.[ContactID] = S.[ContactID]
WHERE
C.Contact_Inactive = 0 AND
S.Mailing_ID = 1 AND
S.Subscribed = 1
)
select * from cteData where RowNum = 1;
In short, one mailing will go out to the person with the last / first name closets to A.
You can do use row_number() and a subquery:
select <list of columns you want>
from (SELECT row_number() over (partition by Contact_Address1, Contact_Address2, Contact_Zip
order by ContactId
) as seqnum
dbo_Contact.Contact_Title AS Title,
dbo_Contact.Contact_FirstName AS [First Name],
dbo_Contact.Contact_LastName AS [Last Name],
dbo_Contact.Contact_Suffix AS Suffix,
dbo_Contact.Business_Name AS [Business Name],
dbo_Contact.Contact_Address1 AS [Address 1],
dbo_Contact.Contact_Address2 AS [Address 2],
dbo_Contact.Contact_City AS City,
dbo_Contact.Contact_State AS State,
dbo_Contact.Contact_Zip AS Zip,
dbo_Contact.Contact_Email AS Email
FROM dbo_Contact
INNER JOIN
dbo_Mailing_Subscribers ON dbo_Contact.[ContactID] = dbo_Mailing_Subscribers.[ContactID]
WHERE
(((dbo_Contact.Contact_Inactive) = False)
AND ((dbo_Mailing_Subscribers.Mailing_ID) = True)
AND ((dbo_Mailing_Subscribers.Subscribed) = True))
) t
where seqnum = 1;
It is unclear what you mean by the "same address" and by "the first contact". For address, the query uses the two address lines and the zip code. FOr "first contact" the query uses the lowest id in the contact table.
Related
I have an employee index, that I need to run queries on for each employee, and display that output along with the original employee.
So say the employee index has an ID, batch, status, and multiple other columns. I have a table where I keep track of every time a column in the employee index changes. I want to display and later export dates of when certain columns use to equal other values, right along side the original employee row.
Naturally I tried creating a form to display multiple value, added a text box to hold my extra information, and changed the value of the text box for each Form_Current event in VBA.
Private Sub Form_Current()
Me.txtPhaseOne = SimpleLookup("SELECT TOP 1 ChangeDate FROM EmployeeVariables WHERE VariableName = ""Batch"" AND EmployeeID = " & Me.Recordset("ID Number") & " ORDER BY ChangeDate ASC", "ChangeDate")
End Sub
It seemed to work at first...
Until I realized the dates were set to whatever the current record date should be
[
So then I tried a join:
SELECT
EmployeeIndex.[ID Number],
EmployeeIndex.Batch,
EmployeeIndex.Status,
EmployeeIndex.[First name],
EmployeeIndex.[Last name],
EVA.ChangeDate as Phase1
FROM
EmployeeIndex
(SELECT TOP 1 ChangeDate FROM EmployeeVariables WHERE EmployeeID = EmployeeIndex.[ID Number] ORDER BY CHangeDate) EVA
Which would work, if I could some how prefetch EmployeeIndex.[ID Number]. (I didn't name these columns) Except I haven't got the slightest clue and I'm running on fumes.
SELECT
EmployeeIndex.[ID Number],
EmployeeIndex.Batch,
EmployeeIndex.Status,
EmployeeIndex.[First name],
EmployeeIndex.[Last name],
EVA.ChangeDate as Phase1
FROM
EmployeeIndex
INNER JOIN
(SELECT TOP 1 EmployeeID, ChangeDate FROM EmployeeVariables WHERE ORDER BY ChangeDate) EVA
ON EmployeeIndex.[ID Number] = EVA.EmployeeID
Try with a subquery:
SELECT
EmployeeIndex.[ID Number],
EmployeeIndex.Batch,
EmployeeIndex.Status,
EmployeeIndex.[First name],
EmployeeIndex.[Last name],
(SELECT Max(EVA.ChangeDate)
FROM EmployeeVariables AS EVA
WHERE EVA.EmployeeID = EmployeeIndex.[ID Number]) AS Phase1
FROM
EmployeeIndex
Cross Apply will be perfect for your TOP 1 case, as it will run for each employeeID rather than just joining on 1
I have the below query/subquery. I am trying to get the CIty, State, and Zipcode from the record in the AOD table and the First and Last from the Employee Original Date table. Can anyone provide guidance on how to extract the data form the sub query? Thank you!
SELECT eod.FIRST_NAME
,eod.LAST_NAME
,eod.SSN
,aodf.SSN
,aodf.CITY
,aodf.STATE
,aodf.ZipCode
FROM EMPLOYEE_ORIG_DATE eod
JOIN
(SELECT aod.ORIG_DATE
,aod.SSN
,aod.ADDRESS_KEY
,aod.Address_1 as AddressLine1
,aod.Address_2 as AddressLine2
,aod.City
,aod.State
,aod.Zip as ZipCode
,aod.Country as CountryCode
,aod.Telephone as HomeNumber
FROM ADDRESS_ORIG_DATE aod
INNER JOIN
(SELECT SSN, MAX(ORIG_DATE) ORIG_DATE
FROM ADDRESS_ORIG_DATE
GROUP BY SSN) aod2
ON aod.SSN = aod2.SSN
AND aod.ORIG_DATE = aod2.ORIG_DATE) aodf
ON eod.SSN = aodf.SSN
AND eod.ADRESS_KEY = aodf.ADDRESS_KEY
WHERE EMPLOYEE_ORIG_DATE.P_COMPANY_ID_I = 3149
If you ask for rewriting to simplify the query, then you may consider using DENSE_RANK() analytic function to include all the matching ties for returning records :
SELECT CITY, STATE, ZipCode, FIRST_NAME, LAST_NAME
FROM
(
SELECT eod.FIRST_NAME,
eod.LAST_NAME,
eod.SSN,
aod.SSN,
aod.CITY,
aod.STATE,
aod.ZipCode,
DENSE_RANK() OVER ( PARTITION BY SSN ORDER BY ORIG_DATE DESC ) ORIG_DATE
FROM EMPLOYEE_ORIG_DATE eod
JOIN ADDRESS_ORIG_DATE aod
ON eod.SSN = aod.SSN
AND eod.ADRESS_KEY = aod.ADDRESS_KEY
WHERE P_COMPANY_ID_I = 3149
)
WHERE ORIG_DATE = 1
where PARTITION BY replaces GROUP BY, and ORIG_DATE DESC replaces MAX(ORIG_DATE)
If you just want the most recent row from ADDRESS_ORIG_DATE for each SSN in EMPLOYEE_ORIG_DATE, then I would expect window functions.
I am guessing you just want one row, even if there are duplicates on the most recent date, so I recommend ROW_NUMBER():
SELECT eod.*, aod.*
FROM EMPLOYEE_ORIG_DATE eod JOIN
(SELECT aod.*,
ROW_NUMBER() OVER (PARTITION BY aod.SSN ORDER BY ORIG_DATE DESC) as seqnum
FROM ADDRESS_ORIG_DATE aod
) aod
ON aod.SSN = eod.SSN
WHERE aod.seqnum = 1 AND
eod.P_COMPANY_ID_I = 3149
I am new at SQL and I am just trying to add two SQL statements together which are below. The first table is a basic make table pulling in only fields I need and then the second table is pulling the same information but appending it to the first table I made in Step 1 . I have been doing some research and what I think I need to do is a union query but I am not sure how to go about that any help please?
/*first step*/
/*Select
[NPI],
[Last Name],
[First Name],
[Middle Name],
Suffix,
Gender,
[Spoken Languages]
Into [Provider Table]
From sylvia.dbo.UNIQUEACN*/
/*Second step appending PCCN Providers*/
Insert into [sylvia].dbo.[provider Table] ( NPI, [Last Name], [First Name], [Middle Name], Suffix, Gender, [spoken languages] )
Select sylvia.dbo.[PCCNProviders].NPI, sylvia.dbo.PCCNProviders.[Last Name],sylvia.dbo.PCCNProviders.[First Name], sylvia.dbo.PCCNProviders.[Middle Name], sylvia.dbo.PCCNProviders.suffix, sylvia.dbo.PCCNProviders.gender, sylvia.dbo.PCCNProviders.[Spoken Languages]
From sylvia.dbo.[PCCNproviders];
Because your 2 tables have the same number and order of columns, you can simply execute the below query. Use UNION ALL if you want to keep duplicated values from both tables or just UNION if you want all duplicated values to be removed.
SELECT *
-- INTO [Combined_table]
FROM sylvia.dbo.UNIQUEACN
UNION ALL
SELECT *
FROM sylvia.dbo.[PCCNproviders]
Thank you I did just that I did a union query and its way cleaner then what I was doing .. Thanks again!! Ive been doing SQL for a week and as you can tell its a struggle but getting there
Select
a.[NPI],
a.[Last Name],
a.[First Name],
a.[Middle Name],
a.Suffix,
a.Gender,
a.[Spoken Languages]
Into [Provider test]
From sylvia.dbo.UNIQUEACN a
Union
Select
b.[NPI],
b.[Last Name],
b.[First Name],
b.[Middle Name],
b.Suffix,
b.Gender,
b.[Spoken Languages]
From sylvia.dbo.[PCCNproviders] b
I have the following data in SQL (nvarchar, nvarchar)
Name: Test Person
Phone Number: 290831283
Fax Number: 192389182
Email Address: test#test.com
Name: Abacus Testing
Phone Number: 901823908
Fax Number: 9213989182
Email Address: abacus#test.com
How can I format this data to be:
[Name] [Phone Number] [Fax Number] [Email Address]
Test Person 290831283 192389182 test#test.com
Abacus Testing 901823908 9213989182 abacus#test.com
So basically setting the rows into matching column
I was hoping to use a Pivot table, but I only get the first row due to aggregation.
SELECT [Name], [Phone Number], [Fax Number], [Email Address]
FROM
(
SELECT
ColumnName,
Data
FROM
TheData
) SRC
PIVOT
(
MAX(Data)
FOR ColumnName IN ([Name], [Phone Number], [Fax Number], [Email Address])
) PIV
I would prefer no CURSOR methods, any alternatives?
Edit: added other fields available for use
The other fields available are Label Id for each entry. i.e Name=1, PhoneNumber=2, FaxNumber=3, EmailAddress=4
The common Id for each of the 4 entries is also available. i.e first 4 entries have id 1001, second 4 entries have id 1002
Following clarification in the comments you just need to add CommonId in to your source.
This is not an aggregated or spreading column so it will be used as a grouping column and you will get a row per distinct value of that.
SELECT [Name], [Phone Number], [Fax Number], [Email Address]
FROM
(
SELECT
CommonId,
ColumnName,
Data
FROM
TheData
) SRC
PIVOT
(
MAX(Data)
FOR ColumnName IN ([Name], [Phone Number], [Fax Number], [Email Address])
) PIV
The database I'm accessing has two tables I need to query using DB2 SQL, shown here as nametable and addresstable. The query is for finding all of the people with a certain balance due. The addresses are stored in a separate table to keep track of address changes. In addresstable, the latest address is determined by a sequence number (ADDRSEQUENCE). The AddressID field is present in both tables, and is what ties each person to specific addresses. The highest sequence number is the current address. I need that current address for each person and only that one. I know I'm going to have to use MAX somewhere for the sequence number, but I can't figure out how to position it given the join. Here's my current query, which of course returns all addresses...
SELECT NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
NAMETABLE.NMELASTBUS AS LASTNAME,
NAMETABLE.NAME_FIRST AS FIRSTNAME,
NAMETABLE.BALDUE AS BALANCEDUE,
ADDRESSTABLE.STREETNAME AS ADDR,
ADDRESSTABLE.ADDRLINE2 AS
ADDRLINE2,ADDRESSTABLE.CITYPARISH AS CITY,
ADDRESSTABLE.ADDRSTATE AS STATE,
ADDRESSTABLE.ZIPCODE AS ZIP,
ADDRESSTABLE.ADDIDSEQNO AS ADDRSEQUENCE
FROM NAMETABLE JOIN ADDRESSTABLE ON NAMETABLE.ADDRESSID = ADDRESSTABLE.ADDRESSID
WHERE NAMETABLE.BALANCEDUE >= '50.00'
You can do a sub-select on the MAX(ADDRSEQUENCE) like so:
SELECT
N.ACCTNUM AS ACCOUNTNUMBER
,N.NMELASTBUS AS LASTNAME
,N.NAME_FIRST AS FIRSTNAME
,N.BALDUE AS BALANCEDUE
,A.STREETNAME AS ADDR,
,A.ADDRLINE2 AS
,A.ADDRLINE2
,A.CITYPARISH AS CITY,
,A.ADDRSTATE AS STATE,
,A.ZIPCODE AS ZIP,
FROM NAMETABLE AS N
JOIN ADDRESSTABLE AS A
ON N.ADDRESSID = A.ADDRESSID
WHERE N.BALANCEDUE >= '50.00'
AND A.ADDRSEQUENCE = (
SELECT MAX(ADDRSEQUENCE)
FROM ADDRESSTABLE AS A2
WHERE A.ADDRESSID = A2.ADDRESSID
)
This is pretty quick in DB2.
You can use a row_number and partition by to do this. Something like this:
with orderedaddress as (
select row_number() over (partition by ADDRESSID order by ADDRSEQUENCE desc) as rown,
STREETNAME,ADDRESSID, ... from ADDRESSTABLE
)
select NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
...
oa.STREETNAME
...
from NAMETABLE JOIN orderedaddress oa on NAMETABLE.ADDRESSID = oa.ADDRESSID
where oa.rown = 1
and NAMETABLE.BALANCEDUE >= '50.00'