Search table twice in SQL Server - sql

I've come across this issue several times now and I am not sure how to solve it. I have a query that needs to access the same table twice to pick out two different persons: a consultant and the customer contact.
Consultant + Customer query looks like this
select
CRM7.contact.contact_id as CustomerID,
CRM7.contact.name + ' ' + CRM7.person.firstname + ' ' + CRM7.person.LASTNAME as CustomerName,
CRM7.person.firstname + ' ' + CRM7.person.lastname as ConsultantName,
CRM7.udcontactsmall.long08 as WriteLic,
CRM7.udcontactsmall.long17 as ReadLic,
CRM7.udcontactsmall.long09 as HasMaint,
CRM7.udlist.name as BCVer
from
CRM7.contact,
CRM7.udcontactsmall
left join
CRM7.associate on CRM7.udcontactsmall.long11 = CRM7.associate.associate_id
left join
CRM7.person on CRM7.associate.person_id = CRM7.person.person_id
left join
CRM7.udlist on CRM7.udcontactsmall.long07 = CRM7.udlist.UDList_id
where
CRM7.contact.category_idx = '2' and
CRM7.contact.userdef_id = CRM7.udcontactsmall.udcontactsmall_id
order by
CRM7.contact.name
And the one that gets the contact for each customer looks like this
SELECT
C.NAME+' Kontakt '+ P.FIRSTNAME+' '+P.LASTNAME AS CONTACT
FROM
CRM7.PERSON P
LEFT OUTER JOIN
CRM7.CONTACT C ON P.CONTACT_ID = C.CONTACT_ID
WHERE
C.CATEGORY_IDX IN ('2','5')
AND P.RETIRED = 0
ORDER BY
C.NAME, P.LASTNAME, P.FIRSTNAME
Dataset:
http://oi61.tinypic.com/2j66cjq.jpg
How do I get a query which returns both the consultant for the customer and the customer contact?

This should serve your purpose:
select
CRM7.contact.contact_id as CustomerID
,CRM7.contact.name+' '+CRM7.person.firstname+' '+CRM7.person.LASTNAME as CustomerName
,CRM7.person.firstname+' '+CRM7.person.lastname as ConsultantName
,CRM7.udcontactsmall.long08 as WriteLic
,CRM7.udcontactsmall.long17 as ReadLic
,CRM7.udcontactsmall.long09 as HasMaint
,CRM7.udlist.name as BCVer
,C.NAME+' Kontakt '+ CRM7.person.FIRSTNAME+' '+ CRM7.person.LASTNAME AS CONTACT
from
CRM7.contact
,CRM7.udcontactsmall
left join CRM7.associate on CRM7.udcontactsmall.long11=CRM7.associate.associate_id
left join CRM7.person on CRM7.associate.person_id=CRM7.person.person_id
left join CRM7.udlist on CRM7.udcontactsmall.long07=CRM7.udlist.UDList_id
LEFT OUTER JOIN (SELECT CONTACT_ID,NAME FROM CRM7.CONTACT WHERE CATEGORY_IDX in ('2','5') AND P.RETIRED=0) C ON CRM7.person.CONTACT_ID=C.CONTACT_ID
where
CRM7.contact.category_idx='2'
and CRM7.contact.userdef_id=CRM7.udcontactsmall.udcontactsmall_id
order by
CRM7.contact.name
I have used a join on contact table from the second query and added it into the first one to get customer contacts:
LEFT OUTER JOIN
(SELECT CONTACT_ID, NAME
FROM CRM7.CONTACT
WHERE CATEGORY_IDX IN ('2','5') AND P.RETIRED = 0) C ON CRM7.person.CONTACT_ID = C.CONTACT_ID

Related

Combining multiple row values into a single column

I appreciate that similar questions have been asked before but I'm unsure what to try next, and am under some pressure. I'm trying to combine multiple row values into a single column, and to do this am trying to use XML Path. The following is where I have got to, but I'm now simply displaying multiple instances of multiple subjects in a single column.
Using SQL Server, I'd like to combine all subjects for a given pupil (around 10) into the 'All Subjects' column. can someone point me to where I'm going wrong? Thanks, Gavin
SELECT distinct
P.FORM AS Class,
NAME.NAME AS [Pupil Name],
(SELECT ';' + SS.DESCRIPTION
FROM PUPIL P
INNER JOIN PUPIL_SET PS on PS.PUPIL_ID = P.PUPIL_ID
INNER JOIN SUBJECT_SET SS on SS.SUBJECT_SET_ID = PS.SUBJECT_SET_ID
FOR XML PATH('')) [All Subjects],
NAME_1.TITLE + ' ' + NAME_1.FIRST_NAMES + ' ' + NAME_1.SURNAME AS [Parent or Carer Name],
Replace(isnull(ADDRESS.HOUSE_STREET,'') + ', ' + isnull(ADDRESS.VILLAGE_AREA,'') + ', ' + isnull(ADDRESS.TOWN_CITY,'') + ', ' + isnull(ADDRESS.COUNTY,'') + ', ' + isnull(ADDRESS.COUNTRY,'') + ' ' + isnull(ADDRESS.POST_CODE,''),',,', '') AS Address,
--RELATIONSHIP.RANK,
CASE WHEN NAME.MAIN_ADDRESS_ID = NAME_1.MAIN_ADDRESS_ID THEN 'HOME' ELSE 'OTHER' END AS [Home or Other]
FROM PUPIL P
INNER JOIN NAME ON P.NAME_ID = NAME.NAME_ID
INNER JOIN ADDRESS ON NAME.MAIN_ADDRESS_ID = ADDRESS.ADDRESS_ID
INNER JOIN RELATIONSHIP ON NAME.NAME_ID = RELATIONSHIP.FROM_NAME_ID
INNER JOIN NAME AS NAME_1 ON RELATIONSHIP.TO_NAME_ID = NAME_1.NAME_ID
INNER JOIN PUPIL_SET PS on PS.PUPIL_ID = P.PUPIL_ID
INNER JOIN SUBJECT_SET SS on SS.SUBJECT_SET_ID = PS.SUBJECT_SET_ID
WHERE
(RELATIONSHIP.RANK=1 Or RELATIONSHIP.RANK=2)
AND P.ACADEMIC_YEAR=YEAR(DateAdd(m,-5,getDate()))
AND P.SUB_SCHOOL='030SEN'
AND P.IN_USE='y'
AND P.RECORD_TYPE='1'
AND Len(P.FORM)>0
and p.ACADEMIC_YEAR = 2015;
First, you only need subject_set and pupil_set in the subquery, not the outer query.
Second, you need a correlation clause. So, something like this:
SELECT P.FORM AS Class,
. . .
(SELECT ';' + SS.DESCRIPTION
FROM PUPIL_SET PS INNER JOIN
SUBJECT_SET SS
on SS.SUBJECT_SET_ID = PS.SUBJECT_SET_ID
WHERE PS.PUPIL_ID = P.PUPIL_ID
FOR XML PATH('')
) [All Subjects],
. . .
FROM PUPIL P INNER JOIN
NAME
ON P.NAME_ID = NAME.NAME_ID INNER JOIN
ADDRESS
ON NAME.MAIN_ADDRESS_ID = ADDRESS.ADDRESS_ID INNER JOIN
RELATIONSHIP
ON NAME.NAME_ID = RELATIONSHIP.FROM_NAME_ID INNER JOIN
NAME AS NAME_1
ON RELATIONSHIP.TO_NAME_ID = NAME_1.NAME_ID
WHERE . . .;
You should not need SELECT DISTINCT. You were getting duplicates because of the unnecessary joins.

How to optimize a query - extracting count info using a view

How can I structure the below query to run through multiple databases all at the same time.
To calculate the total number of active users in the db, I currently have to run the query one database at a time.
Is there some kind of foreach function I can run dynamically?
with data as
(select p.CoNum CoNum, p.LastName, p.Name,co.name Company, liGender.Description as Gender, liEth.Description as EthnicGroup,Isnull(Limed.Description,'Not Specified') FinancialAid,
vwPTU.[UserP Type] as UserPType
from UsersP p
left outer join ListItem liGender on liGender.Id = p.Gender
left outer join ListItem liEth on liEth.Id = p.EthnicGroup
left outer join ListItem limed on limed.Id = p.FinancialAidId
inner join UserPOrgNodeAssociation pona on P.Id = pona.UserPId
inner join CoAssociation coda on pona.CoNodeDescAssociationId = coda.Id
inner join Company co on coda.companyid=co.id
left outer join [dbo].[vw_XUserUniqueView] vwPTU on p.Id = vwPTU.Id
and vwPTU.[ValidToDate] > '2015/12/31 23:59 PM'
where vwPTU.[User Type] is not null
)
select Company, count(distinct CoNum) as Total
from data
group by company
Try using SP_MSForEachDB procedure..
exec sp_msforeachdb 'Your Query here'

Query Performance too Slow

Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.

SQL Select with joins across two databases. Confusing :-s

If anyone could help me join these two selects together to create one mega statement that would be awesome!!
--running against quotingSystem database
SELECT
CONVERT (varchar, Quote.QuoteID) AS QuoteID, Quote.FirstName,
Quote.LastName, Quote.ProductSKU, Quote.ProductID, Quote.Quantity,
Quote.CreationDate,
CONVERT (CHAR(8), Quote.CreationTime, 8) AS CreationTime,
Quote.CompanyName,
IncommingQuoteStatus.StatusDesc, Quote.LockedDateTime,
Users.FirstName + ' ' + Users.LastName AS UserName
FROM
Quote
INNER JOIN
IncommingQuoteStatus ON IncommingQuoteStatus.StatusID = Quote.Status
INNER JOIN
Users ON Quote.LockedUserID = Users.UserID
WHERE
(Quote.Status > 2 AND Quote.Status < 6)
ORDER BY
QuoteID DESC
-- running on quoting system database but also pulling in values from another database CBretailDB
select
D2.stock AS CurrentStock
from
dbo.Quote as D1
inner join
CBretailDB.dbo.products AS D2 ON D1.ProductID = D2.idProduct
the Quote.ProductID on the first statement needs to join on the D2.idProduct from second statement to pull the CurrentStock value
I think that makes sense!
Many thanks
Try this:
SELECT CONVERT (varchar, Quote.QuoteID) AS QuoteID, Quote.FirstName, Quote.LastName,
Quote.ProductSKU, Quote.Quantity, Quote.CreationDate, CONVERT (CHAR(8),
Quote.CreationTime, 8) AS CreationTime, Quote.CompanyName,
IncommingQuoteStatus.StatusDesc, Quote.LockedDateTime, Users.FirstName + ' ' +
Users.LastName AS UserName, D2.stock FROM Quote INNER JOIN IncommingQuoteStatus ON
IncommingQuoteStatus.StatusID = Quote.Status INNER JOIN Users ON Quote.LockedUserID =
Users.UserID
INNER JOIN CBretailDB.dbo.products AS D2 ON Quote.ProductID = D2.idProduct
WHERE (Quote.Status > 2 AND Quote.Status < 6) ORDER BY QuoteID DESC

Unified records for database query with Sql

Basic need is if a record has an Attribute of "Urgent", then the attributevalue should be displayed in the Urgent column. If the record has an attribute value of "closed", then the attributevalue must be displayed in the "Closed" column.
I have a query below. My problem is that among the results I am getting back, there are two records with the same RequesterID (one with a valid value in "Urgent" column and one with a value in "Closed" colum)
My problem is that I need these two particular records to be displayed as one record.
Any ideas?
SELECT DISTINCT
r.RequesterID,
sr.ModifiedDate,
p.FirstName + ' ' + p.LastName AS RequesterName,
CASE
WHEN sa.Attribute = 'Urgent' THEN sa.AttributeValue
ELSE NULL
END AS Urgent,
CASE
WHEN sa.Attribute = 'Closed' THEN sa.AttributeValue
ELSE NULL
END AS Closed
FROM
Requester AS r
INNER JOIN SubRequester AS sr
ON r.RequesterID = sr.RequesterID
INNER JOIN SubRequesterAttribute AS sa
ON sr.SubRequesterID = sa.SubRequesterID
CROSS JOIN Personnel AS p
WHERE
(r.UserID = p.ContractorID
OR r.UserID = p.EmployeeID)
AND
(sa.Attribute IN ('Urgent', 'Closed'))
GROUP BY r.RequesterID, sr.ModifiedDate, p.FirstName, p.LastName,
sa.Attribute, sa.AttributeValue
You will need to join to your sub requester attribute table to the query twice. One with the attribute of Urgent and one with the attribute of Close.
You will need to LEFT join to these for the instances where they may be null and then reference each of the tables in your SELECT to show the relevent attribute.
I also wouldn't reccomend the cross join. You should perform your "OR" join on the personnel table in the FROM clause rather than doing a cross join and filtering in the WHERE clause.
EDIT: Sorry, my first response was a bit rushed. Have now had a chance to look further. Due to the sub requester and the sub requester attribute both being duplicates you need to split them both up into a subquery. Also, your modified date could be different for both values. So i've doubled that up. This is completely untested, and by no means the "optimum" solution. It's quite tricky to write the query without the actual database to check against. Hopefully it will explain what I meant though.
SELECT
r.RequesterID,
p.FirstName + ' ' + p.LastName AS RequesterName,
sra1.ModifiedDate as UrgentModifiedDate,
sra1.AttributeValue as Urgent,
sra2.ModifiedDate as ClosedModifiedDate,
sra2.AttributeValue as Closed
FROM
Personnel AS p
INNER JOIN
Requester AS r
ON
(
r.UserID = p.ContractorID
OR
r.UserID = p.EmployeeID
)
LEFT OUTER JOIN
(
SELECT
sr1.RequesterID,
sr1.ModifiedDate,
sa1.Attribute,
sa1.AttributeValue
FROM
SubRequester AS sr1
INNER JOIN
SubRequesterAttribute AS sa1
ON
sr1.SubRequesterID = sa1.SubRequesterID
AND
sa1.Attribute = 'Urgent'
) sra1
ON
sra1.RequesterID = r.RequesterID
LEFT OUTER JOIN
(
SELECT
sr2.RequesterID,
sr2.ModifiedDate,
sa2.Attribute,
sa2.AttributeValue
FROM
SubRequester AS sr2
INNER JOIN
SubRequesterAttribute AS sa2
ON
sr2.SubRequesterID = sa2.SubRequesterID
AND
sa2.Attribute = 'Closed'
) sra1
ON
sra2.RequesterID = r.RequesterID
SECOND EDIT: My last edit was that there were multiple SubRequesters as well as multiple Attribute, from your last comment you want to show all SubRequesters and the two relevent attributes? You can achieve this as follows.
SELECT
r.RequesterID,
p.FirstName + ' ' + p.LastName AS RequesterName,
sr.ModifiedDate,
sa1.AttributeValue as Urgent,
sa2.AttributeValue as Closed
FROM
Personnel AS p
INNER JOIN
Requester AS r
ON
(
r.UserID = p.ContractorID
OR
r.UserID = p.EmployeeID
)
INNER JOI N
SubRequester as sr
ON
sr.RequesterID = r.RequesterID
LEFT OUTER JOIN
SubRequesterAttribute AS sa1
ON
sa1.SubRequesterID = sr.SubRequesterID
AND
sa1.Attribute = 'Urgent'
LEFT OUTER JOIN
SubRequesterAttribute AS sa2
ON
sa2.SubRequesterID = sr.SubRequesterID
AND
sa2.Attribute = 'Closed'
Generally, if you have multiple rows and want to collapse them into one, GROUP BY is the basic tool to achieve that. It looks like you tried to go in that direction but didn't quite get there. What you want to do is group by the expressions that are duplicated between the rows, and apply group functions to the other expressions that will eliminate the NULL values. I used MIN in the example below but you could just as easily use MAX; the point is that since at most one of the rows will have a value for that expression, that value is both the minimum and the maximum.
SELECT
r.RequesterID,
sr.ModifiedDate,
p.FirstName + ' ' + p.LastName AS RequesterName,
MIN(
CASE
WHEN sa.Attribute = 'Urgent' THEN sa.AttributeValue
ELSE NULL
END
) AS Urgent,
MIN(
CASE
WHEN sa.Attribute = 'Closed' THEN sa.AttributeValue
ELSE NULL
END
) AS Closed
FROM
Requester AS r
INNER JOIN SubRequester AS sr
ON r.RequesterID = sr.RequesterID
INNER JOIN SubRequesterAttribute AS sa
ON sr.SubRequesterID = sa.SubRequesterID
CROSS JOIN Personnel AS p
WHERE
(r.UserID = p.ContractorID
OR r.UserID = p.EmployeeID)
AND
(sa.Attribute IN ('Urgent', 'Closed'))
GROUP BY r.RequesterID, sr.ModifiedDate, p.FirstName + ' ' + p.LastName