Joining SQL tables - sql

I have a customer table that has primary information about the customer like, name, lastname,password,… I have a Address, Email, Phone table that has for example 3 kinds of address , 2 phone number, 2 email address for each customer. I have a Type table that TypeID and Type_Group,Type_Value. For example:
TypeID Type_Group Type_Value
1 Address Work
2 Address Home
3 Address mailing
4 Email Primary
5 Email secondary
I know how to join customer table with address, Email and phone table. I don't know how to join the Address, phone,Email with type Table.
This is my Query:
SELECT
cc.[Customer_ID]
,[Account_Number]
,[First_Name]
,[Middle_Name]
,[Last_Name]
,[Password]
,ce.[Email]
,cph.Phone_Number
,ca.Address_1
,ca.Address_2
,ca.City
,ca.State
,ca.Zip
,tp.Type_Desc
FROM [CustomerPortal].[dbo].[Customer] cc WITH (NOLOCK)
left join [CustomerPortal].[dbo].Customer_Email ce WITH (NOLOCK) on cc.Customer_ID = ce.Customer_ID
left join [CustomerPortal].[dbo].Customer_Address ca WITH (NOLOCK) on cc.Customer_ID =cp.Customer_ID
left join [CustomerPortal].[dbo].Customer_Phone cph WITH (NOLOCK) on cc.Customer_ID =cph.Customer_ID
WHERE cc.Customer_ID=#Customer_ID
This is Tables:
this is customer Table:
(PRIMARY KEY)[Customer_ID] [int] IDENTITY(1,1) NOT NULL,
[Account_Number] [int] NULL,
[First_Name] [varchar](50) NULL,
[Middle_Name] [varchar](50) NULL,
Customer Address Table:
[dbo].[Customer_Address](
primary key[Customer_Address_ID] [int] IDENTITY(1,1) NOT NULL,
Fkey [Customer_ID] [int] NOT NULL,
[Address_1] [varchar](100) NULL,
[Address_2] [varchar](100) NULL,
[City] [varchar](100) NULL,
[State] [varchar](10) NULL,
[Zip] [varchar](10) NULL,
Fkey [Address_Type] [int] NULL,
CustomerEmail Table:
[dbo].[Customer_Email](
PKey [Customer_Email_ID] [int] IDENTITY(1,1) NOT NULL,
Fkey [Customer_ID] [int] NOT NULL,
[Email] [varchar](50) NULL,
Fkey [Email_Type] [int] NULL,
Customer Phone Table:
PK [dbo].[Customer_Phone](
FK [Customer_Phone_ID] [int] IDENTITY(1,1) NOT NULL,
[Customer_ID] [int] NOT NULL,
[Phone_Number] [bigint] NULL,
FK [Phone_Type] [int] NULL,
Type Table:
PK [dbo].[Type_XREF](
[Type_ID] [int] IDENTITY(1,1) NOT NULL,
[Type_Group] [varchar](25) NULL,
[Type_Value] [varchar](50) NULL,
[Type_Desc] [varchar](100) NULL,
I am not sure how to add join to Type Table, any thing I try produce me several Rows, as I want to have 1 row for customer with name, All related Home address,All related mailing address, primary email,secondary email,.... So all customer info in 1 line of record.

You can join each of the tables to the type table seperately, since their Type ID will correspond to one of the IDs in the type table. Even though the types are mixed in the table, each element in their respective table would reasonable have a logical type assigned to it. I'll just make an assumption on the format that you want to display the Type in and the name of the table:
SELECT
cc.[Customer_ID]
,[Account_Number]
,[First_Name]
,[Middle_Name]
,[Last_Name]
,[Password]
,ce.[Email]
,cph.Phone_Number
,ca.Address_1
,ca.Address_2
,ca.City
,ca.State
,ca.Zip
,tp.Type_Desc
,te.Type_Group + '-' + te.Type_Value as [EmailType]
,ta.Type_Group + '-' + ta.Type_Value as [AddressType]
,tph.Type_Group + '-' + tph.Type_Value as [PhoneType]
FROM [CustomerPortal].[dbo].[Customer] cc WITH (NOLOCK)
left join [CustomerPortal].[dbo].Customer_Email ce WITH (NOLOCK) on cc.Customer_ID = ce.Customer_ID
left join [CustomerPortal].[dbo].Customer_Address ca WITH (NOLOCK) on cc.Customer_ID =cp.Customer_ID
left join [CustomerPortal].[dbo].Customer_Phone cph WITH (NOLOCK) on cc.Customer_ID =cph.Customer_ID
left join [dbo].Type_Table te on te.ID = ce.Type
left join [dbo].Type_Table ta on ta.ID = ca.Type
left join [dbo].Type_Table tph on tph.ID = cph.Type

Related

SQL Server: select records, not linked to another table

I have a table:
CREATE TABLE [dbo].[CollectionSite]
(
[SiteCode] [nvarchar](32) NOT NULL,
[AddressId] [int] NOT NULL,
[RemittanceId] [int] NULL,
// additional columns
)
and a linked table:
CREATE TABLE [dbo].[CollectionSiteAddress]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](255) NULL,
[Address1] [nvarchar](255) NULL,
[Address2] [nvarchar](255) NULL,
[City] [nvarchar](128) NULL,
[State] [nvarchar](64) NULL,
[Zip] [nvarchar](32) NULL,
)
Relationship between these 2 tables:
ALTER TABLE [dbo].[CollectionSite] WITH CHECK
ADD CONSTRAINT [FK_CollectionSite_CollectionSiteAddress_AddressId]
FOREIGN KEY([AddressId]) REFERENCES [dbo].[CollectionSiteAddress] ([Id])
GO
ALTER TABLE [dbo].[CollectionSite] WITH CHECK
ADD CONSTRAINT [FK_CollectionSite_CollectionSiteAddress_RemittanceId]
FOREIGN KEY([RemittanceId]) REFERENCES [dbo].[CollectionSiteAddress] ([Id])
GO
I want to select all records from CollectionSiteAddress, which are not linked to CollectionSite (neither AddressId nor RemittanceId). Which request should I use?
I tried:
SELECT *
FROM CollectionSiteAddress
LEFT JOIN CollectionSite ON CollectionSiteAddress.Id = CollectionSite.AddressId
OR CollectionSiteAddress.Id = CollectionSite.RemittanceId
but it selects all records from CollectionSiteAddress
You are missing this WHERE clause:
WHERE CollectionSite.[SiteCode] IS NULL
because you want all the unmatched rows of CollectionSiteAddress.
I used the column [SiteCode] to check if it is NULL because it is not nullable in the definition of the table.
So you can write your query like this (shortened with aliases):
SELECT csa.*
FROM CollectionSiteAddress csa LEFT JOIN CollectionSite cs
ON csa.Id = cs.AddressId OR csa.Id = cs.RemittanceId
WHERE cs.[SiteCode] IS NULL
Or use NOT EXISTS:
SELECT csa.*
FROM CollectionSiteAddress csa
WHERE NOT EXISTS (
SELECT 1
FROM CollectionSite cs
WHERE csa.Id = cs.AddressId OR csa.Id = cs.RemittanceId
)

SQL: One 2 many rows with many rows combined into one column

I have four tables, namely tblProject (one record), tblTeamMembers (many records), tblProjectStatus (look-up table) and tblProjectScoresComments (many records). I'm using SQL Server 2017.
Below are the table definitions:
tblProject:
[ProjectID] [INT] IDENTITY(1,1) NOT NULL,
[ProjectName] [NVARCHAR](150) NOT NULL,
[CommunityProblem] [NTEXT] NOT NULL,
[IctSolveCommunityProblem] [NTEXT] NOT NULL,
[TeamMemberRoles] [NTEXT] NOT NULL,
[ProjectImpact] [NTEXT] NOT NULL,
[HelpRaiseFunds] [NTEXT] NOT NULL,
[ProjectStatus] [INT] NOT NULL,
[CaptureDate] [DATE] NOT NULL
tblTeamMembers:
[MemberID] [INT] IDENTITY(1,1) NOT NULL,
[Person] [NVARCHAR](150) NOT NULL,
[SalRef] [NVARCHAR](50) NOT NULL,
[Email] [NVARCHAR](150) NOT NULL,
[UserName] [NVARCHAR](150) NOT NULL,
[TeamLeader] [INT] NOT NULL,
[ProjectLeader] [INT] NOT NULL,
[ProjectLeaderContactNo] [NVARCHAR](150) NULL,
[ProjectID] [INT] NOT NULL
tblProjectScoresComments
[RecID] [INT] IDENTITY(1,1) NOT NULL,
[ProjectID] [INT] NOT NULL,
[Score] [FLOAT] NOT NULL,
[Comments] [NVARCHAR](MAX) NULL,
[UserID] [NVARCHAR](150) NOT NULL,
[DateCaptured] [DATETIME] NOT NULL
tblProjectStatus:
[ProjectStatusID] [INT] IDENTITY(1,1) NOT NULL,
[ProjectStatus] [NVARCHAR](100) NOT NULL
I would like the results to return columns from all three tables, but the 3rd table (tblProjectScoresComments) has many records and for the column [Score] an average should be returned, and the [Comments] column should have all comments returned as 1 column and every comment should be separated by a comma (,).
I would like to use a query similar to the below:
SELECT
p.ProjectID, p.ProjectName AS Project,
ps.ProjectStatus,
tm.Person AS ProjectLeader,
p.CaptureDate, [AVERAGE_SCORE_FOR_ALL] AS Score,
[ALL_COMMENTS_MERGED_TO_ONE_COLUMN] AS Comments
FROM
dbo.tblProject AS p
INNER JOIN
dbo.tblProjectStatus AS ps ON p.ProjectStatus = ps.ProjectStatusID
INNER JOIN
dbo.tblTeamMembers AS tm ON p.ProjectID = tm.ProjectID
INNER JOIN
dbo.tblProjectScoresComments AS psc ON p.ProjectID = psc.ProjectID
WHERE
(tm.ProjectLeader = 1)
Results should look something like this:
ProjectID | Project | ProjectStatus | ProjectLeader | CaptureDate | Score |Comments
---------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | Access to ICT-Makatane High School and Community Project | Not yet decided | Mary Ndlovu | 2019-10-04 | 1.67 |Comment 1,Comment 2,Comment 3
2 | Asample project | Rejected | Joe Soap | 2019-11-07 | 3 |Comment 1,Comment 2
Would really appreciate assistance!
This sounds like aggregation:
SELECT p.ProjectID, p.ProjectName AS Project, ps.ProjectStatus, tm.Person AS ProjectLeader,
p.CaptureDate,
avg(psc.score) AS avg_score,
string_agg(psc.comments, ' ') as Comments
FROM dbo.tblProject p JOIN
dbo.tblProjectStatus ps
ON p.ProjectStatus = ps.ProjectStatusID JOIN
dbo.tblTeamMembers tm
ON p.ProjectID = tm.ProjectID JOIN
dbo.tblProjectScoresComments
psc
ON p.ProjectID = psc.ProjectID
WHERE tm.ProjectLeader = 1
GROUP BY p.ProjectID, p.ProjectName AS Project, ps.ProjectStatus, tm.Person AS ProjectLeader,
p.CaptureDate;
EDIT:
The alternative to string_agg() is rather messy:
SELECT . . .,
psc.avg_score, c.comments,
FROM dbo.tblProject p JOIN
dbo.tblProjectStatus ps
ON p.ProjectStatus = ps.ProjectStatusID JOIN
dbo.tblTeamMembers tm
ON p.ProjectID = tm.ProjectID OUTER APPLY
(SELECT STUFF( (SELECT ', ' + psc.comment
FROM dbo.tblProjectScoresComments psc
WHERE p.ProjectID = psc.ProjectID
FOR XML PATH (''), TYPE
).value(N'.[1]', N'nvarchar(max)'
), 1, 2, ''
) as comments
) c OUTER APPLY
(SELECT AVG(psc.score) as avg_score
FROM dbo.tblProjectScoresComments psc
WHERE p.ProjectID = psc.ProjectID
) psc
An outer GROUP BY should not be necessary.

Repeat data issues SQL

Had a quick browse to see if any previous questions related to my issue, couldn't see any.
Basically I'm doing this database for my online Cert IV course and if I weren't completely stuck (as I have been for the past few months) I wouldn't be asking for major help on this
I've got an Antiques database that is supposed to show the Customer Name, Sales Date, Product Name and Sales Price and only list the items that were sold between 2 dates and order them by said dates. Nothing I do results in not having repeat data
I've got 4 tables for this particular query Customers, Sales and Products, Tables are set up like this:
CREATE TABLE [dbo].[Customers](
[CustID] [int] IDENTITY(1,1) NOT NULL,
[firstName] [varchar](50) NOT NULL,
[lastName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[Sales](
[SalesNo] [int] IDENTITY(1,1) NOT NULL,
[CustID] [int] NOT NULL,
[salesDate] [date] NOT NULL,
CONSTRAINT [PK_Sales] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[prodName] [varchar](50) NOT NULL,
[prodYear] [int] NOT NULL,
[prodType] [varchar](50) NOT NULL,
[salesPrice] [money] NOT NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[ProductSales](
[ProductID] [int] NOT NULL,
[SalesNo] [int] NOT NULL
My query looks like this
SELECT (Customers.firstName + ' ' + Customers.lastName) AS Customers_Name,
Sales.salesDate, Products.prodName, Sales.salesPrice
FROM Customers, ProductSales JOIN Products ON ProductSales.ProductID = Products.ProductID
JOIN Sales ON ProductSales.SalesNo = Sales.SalesNo
WHERE Sales.salesDate BETWEEN '2016-06-03' AND '2016-06-06'
ORDER BY Sales.salesDate
This is what shows up when I run this query:
Any help would be appreciated.
Try below - you need to join customer table properly
SELECT (Customers.firstName + ' ' + Customers.lastName) AS Customers_Name,
Sales.salesDate, Products.prodName, Sales.salesPrice
FROM ProductSales JOIN Products ON ProductSales.ProductID = Products.ProductID
JOIN Sales ON ProductSales.SalesNo = Sales.SalesNo
JOIN Customers on Sales.[CustID]=Customers.[CustID]
WHERE Sales.salesDate BETWEEN '2016-06-03' AND '2016-06-06'
ORDER BY Sales.salesDate

SQL Query - Complex query between tables

I currently have the 5 following tables. Each Site has (1 or Many) Project Managers as well as (1 or Many) Site_Supervisors. A Project Manager / Site Supervisor can be assigned to many sites
I currently have a working query:
SELECT Sites.Site_Name, Sites.Site_Street_Address, Sites.Site_Suburb, Sites.Site_State, Sites.Site_Postcode, Sites.Site_Region, Sites.Completed, Project_Managers.First_Name AS PM_First_Name, Project_Managers.Last_Name AS PM_Last_Name, Site_Supervisors.First_Name AS SS_First_Name, Site_Supervisors.Last_Name AS SS_Last_Name, Sites.Date_Started
FROM Site_Site_Supervisors INNER JOIN
Site_Supervisors ON Site_Site_Supervisors.Site_Supervisor_ID = Site_Supervisors.Site_Supervisor_ID RIGHT OUTER JOIN
Sites ON Site_Site_Supervisors.Site_ID = Sites.Site_ID LEFT OUTER JOIN
Project_Managers INNER JOIN
Site_Project_Managers ON Project_Managers.Project_Manager_ID = Site_Project_Managers.Project_Manager_ID ON
Sites.Site_ID = Site_Project_Managers.Site_ID
WHERE (Sites.Completed = 0)
ORDER BY Sites.Site_Name
Which gives me the desired output, which i then work with in my code.
I am wanting to make a change to the query, where instead of outputting the:
Project_Managers.First_Name AS PM_First_Name
Project_Managers.Last_Name AS PM_Last_Name
instead i replace these with:
Project_Managers.First_Name where the corresponding Site_Project_Managers.Primary_Contact = True AS PM_First_Name
Project_Managers.Last_Name where the corresponding Site_Project_Managers.Primary_Contact = True AS PM_Last_Name
Project_Managers.First_Name where the corresponding Site_Project_Managers.Primary_Contact = False AS AssistantPM_First_Name
Project_Managers.Last_Name where the corresponding Site_Project_Managers.Primary_Contact = False AS AssistantPM_Last_Name
To perform this query is beyond my SQL skillset at this time, so i am hoping one of you can provide me with the correct query to use and or some guidance
Thanks
Sites
[Site_ID] [int] IDENTITY(1,1) NOT NULL (PK),
[Site_Name] [varchar](50) NOT NULL,
[Site_Street_Address] [varchar](50) NULL,
[Site_Suburb] [varchar](50) NULL,
[Site_State] [varchar](50) NULL,
[Site_Postcode] [varchar](10) NULL,
[Site_Region] [varchar](50) NULL,
[Date_Started] [datetime] NULL,
[Completed] [bit] NOT NULL
Project_Managers
[Project_Manager_ID] [int] IDENTITY(1,1) NOT NULL (PK),
[First_Name] [varchar](50) NOT NULL,
[Last_Name] [varchar](50) NOT NULL,
[Phone_Number] [varchar](50) NULL,
[Email_Address] [varchar](50) NULL,
[Currently_Employed] [bit] NOT NULL,
CONSTRAINT [PK_Project_Managers] PRIMARY KEY CLUSTERED
Site_Supervisors
[Site_Supervisor_ID] [int] IDENTITY(1,1) NOT NULL (PK),
[First_Name] [varchar](50) NOT NULL,
[Last_Name] [varchar](50) NOT NULL,
[Phone_Number] [varchar](50) NULL,
[Email_Address] [varchar](50) NULL,
[Currently_Employed] [bit] NOT NULL,
CONSTRAINT [PK_Site_Supervisors_1] PRIMARY KEY CLUSTERED
Site_Project_Managers
[Site_ID] [int] NOT NULL (PK),
[Project_Manager_ID] [int] NOT NULL (PK),
[Primary_Contact] [bit] NULL,
[Alerts] [bit] NULL,
CONSTRAINT [PK_Site_Project_Managers] PRIMARY KEY CLUSTERED
Site_Site_Supervisors
[Site_ID] [int] NOT NULL (PK),
[Site_Supervisor_ID] [int] NOT NULL (PK),
[Primary_Contact] [bit] NULL,
[Alerts] [bit] NULL,
CONSTRAINT [PK_Site_Site_Supervisors] PRIMARY KEY CLUSTERED
Assumed you are using MySql and you may use the CASE or inline IF ELSE to get the desired output that you want
SELECT Sites.Site_Name,
Sites.Site_Street_Address,
Sites.Site_Suburb,
Sites.Site_State,
Sites.Site_Postcode,
Sites.Site_Region,
Sites.Completed,
CASE Site_Project_Managers.Primary_Contact
WHEN true THEN Project_Managers.First_Name
END AS PM_First_Name,
CASE Site_Project_Managers.Primary_Contact
WHEN true THEN Project_Managers.Last_Name
END AS PM_Last_Name,
CASE Site_Project_Managers.Primary_Contact
WHEN false THEN Project_Managers.First_Name
END AS AssistantPM_First_Name,
CASE Site_Project_Managers.Primary_Contact
WHEN false THEN Project_Managers.Last_Name
END AS AssistantPM_Last_Name,
Site_Supervisors.First_Name AS SS_First_Name,
Site_Supervisors.Last_Name AS SS_Last_Name,
Sites.Date_Started
FROM Site_Site_Supervisors
INNER JOIN Site_Supervisors
ON Site_Site_Supervisors.Site_Supervisor_ID = Site_Supervisors.Site_Supervisor_ID
RIGHT OUTER JOIN Sites
ON Site_Site_Supervisors.Site_ID = Sites.Site_ID
LEFT OUTER JOIN Project_Managers
INNER JOIN Site_Project_Managers
ON Project_Managers.Project_Manager_ID = Site_Project_Managers.Project_Manager_ID
ON Sites.Site_ID = Site_Project_Managers.Site_ID
WHERE (Sites.Completed = 0)
ORDER BY Sites.Site_Name

COALESCE vs OR condition for JOIN (SQL)

I have Event table
TABLE Event(
EventId [int] IDENTITY(1,1) NOT NULL,
EventSource1Id [int] NULL,
EventSource2Id [int] NULL
)
that contains info about events from different sources
where one of the event sources can be null
TABLE EventSource1(
Id [int] IDENTITY(1,1) NOT NULL,
Name [nvarchar](50) NULL,
VenueId [int] NOT NULL
)
and
TABLE EventSource2(
Id [int] IDENTITY(1,1) NOT NULL,
Name [nvarchar](50) NULL,
VenueId [int] NOT NULL
)
TABLE Venue(
Id [int] IDENTITY(1,1) NOT NULL,
TimeZone [nvarchar](100) NOT NULL
)
I'd like to create view, but I'm not sure what is the best way to use: coalesce vs OR condition for JOIN
First option:
SELECT
ev.[Id] AS 'Id',
ven.[Id] AS 'VenueId'
FROM Event ev
LEFT JOIN EventSource1 source1 ON source1.[Id] = ev.EventSource1Id
LEFT JOIN EventSource2 source1 ON source2.[Id] = ev.EventSource2Id
LEFT JOIN Venue AS ven ON ven.[Id] = source1.[VenueId] OR v.[Id] = source2.[VenueId]
Second option:
SELECT
ev.[Id] AS 'Id',
ven.[Id] AS 'VenueId'
FROM Event ev
LEFT JOIN EventSource1 source1 ON source1.[Id] = ev.EventSource1Id
LEFT JOIN EventSource2 source1 ON source2.[Id] = ev.EventSource2Id
LEFT JOIN Venue AS ven ON ven.[Id] = COALESCE(source1.[Id], source2.[Id])
Could you help me please?
The COALESCE will typically yield a better query plan. You should test with your data.