Joining two big queries in sql - sql-server

I need to join these two queries ....please help
SELECT P.EMAIL_ADDRESS, ECS.FST_NAME, ECS.LAST_NAME, ECS.COMPANY_NAME, UPPER(P.URL) AS URL,
ECS.COUNTRY, ECS.PER_REGION, ECS.EEA_EMAILABLE_FLG, ECS.PHONEABLE_FLG, ECS.MAILABLE_FLG--INCLUDING THESE FOR INFO ONLY, NOT REQUESTED
--CAST(P.ACTIVITYDATE AS DATE) PGVIST_DATE
FROM [OPSODSADM].[DBO].[ELQR_PAGEVISIT] P WITH (NOLOCK)
JOIN [OPSSOAADM].[DBO].[ELOQUA_CONTACT_STAGE] ECS WITH (NOLOCK) ON P.EMAIL_ADDRESS = ECS.EMAIL_ADDRESS --JOINING TO GET NAME AND COMPANY FIELDS
WHERE ACTIVITYDATE >= '2022-01-01' --STARTING DATE INCLUDED IN MARS REQUEST
AND CHARINDEX('GARTNER.COM', UPPER(P.EMAIL_ADDRESS),1) = 0 --DON'T WANT GARTNER CONTACTS
AND CHARINDEX('RAINFOCUS', UPPER(P.EMAIL_ADDRESS),1) = 0 --DON'T WANT RAINFOCUS CONTACTS
AND (ECS.EVT_EXCL_FLG IS NULL OR ECS.EVT_EXCL_FLG = 'N') --DON'T WANT TO INCLUDE CONTACTS WITH ACTIVE/CURRENT REGISTRATIONS
AND ECS.PER_REGION = 'NA'
AND (UPPER(URL) = 'HTTPS://WWW.GARTNER.COM/EN/CONFERENCES/NA/CFO-FINANCE-US/REGISTER')
--AND CHARINDEX('FES22/RFR', UPPER(URL),1) > 0 --RUN TO SEE ALL VARIATIONS OF RF PAGES BUT ONLY THE RFR/ORDER URL IS WHAT WE TARGET FOR CART ABANDONS
GROUP BY P.EMAIL_ADDRESS, ECS.FST_NAME, ECS.LAST_NAME, ECS.COMPANY_NAME, UPPER(P.URL),
ECS.COUNTRY, ECS.PER_REGION, ECS.EEA_EMAILABLE_FLG, ECS.PHONEABLE_FLG, ECS.MAILABLE_FLG
----ORDER BY P.EMAIL_ADDRESS
SELECT P.EMAIL_ADDRESS, ECS.FST_NAME, ECS.LAST_NAME, ECS.COMPANY_NAME, UPPER(P.URL) AS URL,
ECS.COUNTRY, ECS.PER_REGION, ECS.EEA_EMAILABLE_FLG, ECS.PHONEABLE_FLG, ECS.MAILABLE_FLG --INCLUDING THESE FOR INFO ONLY, NOT REQUESTED
--CAST(P.ACTIVITYDATE AS DATE) PGVIST_DATE
FROM [OPSODSADM].[DBO].[ELQR_PAGEVISIT] P WITH (NOLOCK)
JOIN [OPSSOAADM].[DBO].[ELOQUA_CONTACT_STAGE] ECS WITH (NOLOCK) ON P.EMAIL_ADDRESS = ECS.EMAIL_ADDRESS --JOINING TO GET NAME AND COMPANY FIELDS
WHERE ACTIVITYDATE >= '2022-01-01' --STARTING DATE INCLUDED IN MARS REQUEST
AND CHARINDEX('GARTNER.COM', UPPER(P.EMAIL_ADDRESS),1) = 0 --DON'T WANT GARTNER CONTACTS
AND CHARINDEX('RAINFOCUS', UPPER(P.EMAIL_ADDRESS),1) = 0 --DON'T WANT RAINFOCUS CONTACTS
AND (ECS.EVT_EXCL_FLG IS NULL OR ECS.EVT_EXCL_FLG = 'N') --DON'T WANT TO INCLUDE CONTACTS WITH ACTIVE/CURRENT REGISTRATIONS
AND ECS.PER_REGION = 'NA'
AND (UPPER(URL) = 'HTTPS://REG.GARTNER.COM/FLOW/GARTNER/FES22/RFR/ORDER')
--AND CHARINDEX('FES22/RFR', UPPER(URL),1) > 0 --RUN TO SEE ALL VARIATIONS OF RF PAGES BUT ONLY THE RFR/ORDER URL IS WHAT WE TARGET FOR CART ABANDONS
GROUP BY P.EMAIL_ADDRESS, ECS.FST_NAME, ECS.LAST_NAME, ECS.COMPANY_NAME, UPPER(P.URL),
ECS.COUNTRY, ECS.PER_REGION, ECS.EEA_EMAILABLE_FLG, ECS.PHONEABLE_FLG, ECS.MAILABLE_FLG
--ORDER BY P.EMAIL_ADDRESS
ORDER BY P.EMAIL_ADDRESS

If you want a quick and dirty solution, you could make both queries common table expressions and then join them as you would two normal tables:
with Tab1 AS ([YOUR FIRST BIG QUERY])
,Tab2 AS ([YOUR SECOUND BIG QUERY])
SELECT * FROM Tab1 INNER JOIN Tab2 ON Tab1.[FIELD] = Tab2.[FIELD]
If you want something that will not look so unpleasant, I would recommend taking the URL out and making it a variable, so you can call the script more succinctly and go from there, but that is very reliant on context.

Related

Pivot Values as Column Headers

I have some questions in a table named GeneralReviews_Questions q that I want to use as column headers rather than values. I'm accomplishing this now by sticking the question responses into a #temp table and then joining a second query to get the responses and hard-coding the questions as column names. It works but it's a maintenance nightmare. How do I accomplish this without hard-coding the questions as column names?
SELECT
r.ReviewID,
max(case when q.Sequence = 1 AND q.Category = 'General' AND q.Active = 1 then Response end)
AS [Q1],
max(case when q.Sequence = 2 AND q.Category = 'General' AND q.Active = 1 then Response end)
AS [Q2]
INTO #temp
FROM
GeneralReviews gr INNER JOIN GeneralReviews_Questions_Responses r
ON gr.ReviewID = r.ReviewID INNER JOIN
GeneralReviews_Questions q ON r.QuestionID = q.QuestionID
GROUP BY
r.ReviewID;
SELECT
#temp.ReviewID AS ReviewID
,#temp.[Q1] AS [Q1 For the past four quarters, were the Quarterly Interest Statements sent
if the account and loan type/status required it?]
,#temp.[Q2] AS [Q2 We will focus on 1-2 events (repay plan change, new disbursement, end of
a defer/forb, acct adjustment etc) per qtr?]
FROM
GeneralReviews gr INNER JOIN
#temp ON gr.ReviewID = #temp.ReviewID
Desired Results: https://i.stack.imgur.com/HPnS3.jpg

Update multiple tables with multiple rows with trigger

I have these tables Users, UserPackages, Packages, Refers.
Users table has columns UserRef_NO (his own unique number), RefNo (if he registered using someones reference number) and Refarning (where he/she gets earning if someone registered using his refNo and bought a package and package status changed to 'True').
UserPackages table has columns U_ID (foreign key to Users), P_ID (foreign key to Packages), PackageStatus (true if bought false if not), BuyDate (generated as soon as PackageStatus changes to true), ExpiryDate (calculated from the join of Packages table and BuyDate where validity is total days of Packages)
Packages table has columns Price, ReferComission (in percentage), Validity (in days).
EDIT:- Third Edit this works fine for single row updates but fails for multi row updates saying subquery returned more then one value
alter TRIGGER [dbo].[HeavyTriggerTest] ON [dbo].[UserPackages]
after update
as
update UP set
BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate())
from dbo.UserPackages UP
inner join Inserted I on I.P_ID = UP.P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';
;
with firstCte(Name,UID,PName,Price,ReferComission,ReferredBy)
as
(
select distinct Users.Name,Users.ID,Packages.PName,Packages.Price,Packages.ReferCommission,(select DISTINCT ID from Users
where Users.UserRef_No=Refers.RefOf )
from Users inner join UserPackages on UserPackages.U_ID=Users.ID
inner join Packages on Packages.PID=UserPackages.P_ID
inner join Refers on Users.Ref_No=Refers.RefOf
inner join Inserted I on I.U_ID = UserPackages.U_ID and I.P_ID = UserPackages.P_ID
and UserPackages.PackageStatus='true' AND UserPackages.U_ID=i.U_ID
AND Refers.RefOf=(SELECT users.Ref_No where UserPackages. U_ID=i.U_ID)
)
update Users set RefEarning+= Price*ReferComission/100 from firstCte where ID=ReferredBy ;
update Users set Active='True' where ID=(select U_ID from inserted) and Active='False'
and here's the single update query which i tried to replace with above last two updates but it gives wrong results plus it also doesn't work for multiple row updates
update Users set RefEarning+=(
case when ID=firstCte.ReferredBy then firstCte.Price*ReferComission/100 else RefEarning end)
,Active=case when ID=(select U_ID from inserted) and Active='false' then 'True'
when firstCte.ReferredBy=(select U_ID from inserted) then 'true' else Active end
from firstCte
Your second query, first update, you need to join Inserted on as:
update UP set
BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate())
from dbo.UserPackages UP
inner join Inserted I on I.P_IP = UP_P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';
Note the table aliases which I recommended to you in your last question - they make it much easier to read through a query.
Also note its best practice to schema qualify your tables.
Second query, second update:
with firstCte ([Name], [UID], PName, Price, ReferComission, ReferredBy)
as
(
select U.[Name], U.ID, P.PName, P.Price, P.ReferCommission
, max(U.ID) over () as referedby
from Users U
inner join UserPackages UP on UP.U_ID = U.ID
inner join Packages P on P.PID = UP.P_ID
inner join Refers R on R.RefOf = U.Ref_No
inner join Inserted I on I.U_ID = UP.U_ID and I.P_ID = UP.P_ID
where UP.PackageStatus='true'
)
update U set
Active = 'True'
, RefEarning += Price*ReferComission/100
from Users U
inner join firstCte on ReferredBy = U.id
where Active = 'False';
Note the window function max to avoid repeating the query in a sub-query.
Note joining the CTE to the Users table to perform the update.

SQL combine two queries result into one dataset

I am trying to combine two SQL queries the first is
SELECT
EAC.Person.FirstName,
EAC.Person.Id,
EAC.Person.LastName,
EAC.Person.EmployeeId,
EAC.Person.IsDeleted,
Controller.Cards.SiteCode,
Controller.Cards.CardCode,
Controller.Cards.ActivationDate,
Controller.Cards.ExpirationDate,
Controller.Cards.Status,
EAC.[Group].Name
FROM
EAC.Person
INNER JOIN
Controller.Cards ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN
EAC.GroupPersonMap ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN
EAC.[Group] ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id
And the second one is
SELECT
IsActive, ActivationDateUTC, ExpirationDateUTC,
Sitecode + '-' + Cardcode AS Credential, 'Badge' AS Type,
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GetUTCDate()
THEN 'Pending'
WHEN ExpirationDAteUTC < GetUTCDate()
THEN 'Expired'
ELSE 'Active'
END AS Status
FROM
EAC.Credential
JOIN
EAC.WiegandCredential ON Credential.ID = WiegandCredential.CredentialId
WHERE
PersonID = '32'
Where I would like to run the second query for each user of the first query using EAC.Person.Id instead of the '32'.
I would like all the data to be returned in one Dataset so I can use it in Report Builder.
I have been fighting with this all day and am hoping one of you smart guys can give me a hand. Thanks in advance.
Based on your description in the comments, I understand that the connection between the two datasets is actually the PersonID field, which exists in both EAC.Credential and EAC.Person; however, in EAC.Credential, duplicate values exist for PersonID, and you want only the most recent one for each PersonID.
There are a few ways to do this, and it will depend on the number of rows returned, the indexes, etc., but I think maybe you're looking for something like this...?
SELECT
EAC.Person.FirstName
,EAC.Person.Id
,EAC.Person.LastName
,EAC.Person.EmployeeId
,EAC.Person.IsDeleted
,Controller.Cards.SiteCode
,Controller.Cards.CardCode
,Controller.Cards.ActivationDate
,Controller.Cards.ExpirationDate
,Controller.Cards.Status
,EAC.[Group].Name
,X.IsActive
,X.ActivationDateUTC
,X.ExpirationDateUTC
,X.Credential
,X.Type
,X.Status
FROM EAC.Person
INNER JOIN Controller.Cards
ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN EAC.GroupPersonMap
ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN EAC.[Group]
ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id
CROSS APPLY
(
SELECT TOP 1
IsActive
,ActivationDateUTC
,ExpirationDateUTC
,Sitecode + '-' + Cardcode AS Credential
,'Badge' AS Type
,'Status' =
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GETUTCDATE()
THEN 'Pending'
WHEN ExpirationDateUTC < GETUTCDATE()
THEN 'Expired'
ELSE 'Active'
END
FROM EAC.Credential
INNER JOIN EAC.WiegandCredential
ON EAC.Credential.ID = EAC.WiegandCredential.CredentialId
WHERE EAC.Credential.PersonID = EAC.Person.PersonID
ORDER BY EAC.Credential.ID DESC
) AS X
-- Optionally, you can also add conditions to return specific rows, i.e.:
-- WHERE EAC.Person.PersonID = 32
This option uses a CROSS APPLY, which means that every row of the first dataset will return additional values from the second dataset, based on the criteria that you described. In this CROSS APPLY, I'm joining the two datasets based on the fact that PersonID exists in both EAC.Person (in your first dataset) as well as in EAC.Credential. I then specify that I want only the TOP 1 row for each PersonID, with an ORDER BY specifying that we want the most recent (highest) value of ID for each PersonID.
The CROSS APPLY is aliased as "X", so in your original SELECT you now have several values prefixed with the X. alias, which just means that you're taking these fields from the second query and attaching them to your original results.
CROSS APPLY requires that a matching entry exists in both subsets of data, much like an INNER JOIN, so you'll want to check and make sure that the relevant values exist and are returned correctly.
I think this is pretty close to the direction you're trying to go. If not, let me know and I'll update the answer. Good luck!
Try like this;
select Query1.*, Query2.* from (
SELECT
EAC.Person.FirstName,
EAC.Person.Id as PersonId,
EAC.Person.LastName,
EAC.Person.EmployeeId,
EAC.Person.IsDeleted,
Controller.Cards.SiteCode,
Controller.Cards.CardCode,
Controller.Cards.ActivationDate,
Controller.Cards.ExpirationDate,
Controller.Cards.Status,
EAC.[Group].Name
FROM
EAC.Person
INNER JOIN
Controller.Cards ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN
EAC.GroupPersonMap ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN
EAC.[Group] ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id)
Query1 inner join (SELECT top 100
IsActive, ActivationDateUTC, ExpirationDateUTC,
Sitecode + '-' + Cardcode AS Credential, 'Badge' AS Type,
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GetUTCDate()
THEN 'Pending'
WHEN ExpirationDAteUTC < GetUTCDate()
THEN 'Expired'
ELSE 'Active'
END AS Status
FROM
EAC.Credential
JOIN
EAC.WiegandCredential ON Credential.ID = WiegandCredential.CredentialId
ORDER BY EAC.Credential.ID DESC) Query2 ON Query1.PersonId = Query2.PersonID
Just select two queries to join them like Query1 and Query2 by equaling PersonId data.

SQL boolean EXISTS while using aggregate function

I have written a query that returns the list of all customers that have ever made a purchase with the company I work for. The person for whom I am getting the data would like to know if a specific criteria is true for any of these orders.
select L.ParentLocation,
[Number of Orders] = count(distinct(T.Order))
from Table1 L
join Table2 T
on L.Location = T.Location
group by L.ParentLocation
However, the issue is complicated because I am already grouping by ParentLocation, and each ParentLocation has many normal Locations. So I am counting the number of unique orders at the location level, then grouping them by the ParentLocation.
I want to return 'TRUE' in the query if a field 'OrderDesc' contains "Toys" in ANY of the orders by ANY of the Locations owned by a ParentLocation. Is there a way to do this?
NOTE: Table2 contains the OrderDesc column.
Thanks for reading!
select
L.ParentLocation,
[Number of Orders] = count(distinct(T.Order)),
has_toys = max(case when t.OrderDesc like '%toys%' then 'TRUE' else '' end)
from Table1 L
inner join Table2 T
on L.Location = T.Location
group by
L.ParentLocation

Optimising this query. Relevant for DBA's working on a social network/community type website

I suppose this is quite a common SP present in socialnetworks and community type websites.
I have this SP that returns all of a user's friends on their 'friends' page order by those currently online, then alphabetically. It's taking quite a while to load and I am looking to speed it up.
I remember reading somewhere on SO that breaking up multiple joins into smaller result sets might speed it up. I haven't tried this yet but I am curious to see what other recommendations SO might have on this procedure.
DECLARE #userID INT -- This variable is parsed in
DECLARE #lastActivityMinutes INT
SET #lastActivitytMinutes = '15'
SELECT
Active = CASE WHEN DATEDIFF("n", b.LastActivityDate ,GETDATE()) < #lastActivityMinutes THEN 1 ELSE 0 END,
a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate
FROM
Profile AS a
INNER JOIN aspnet_Users as b on b.userId = a.UserId
LEFT JOIN Friend AS x ON x.UserID = a.UserID
LEFT JOIN Friend AS z ON z.FriendID = a.UserID
WHERE ((x.FriendId = #userID AND x.status = 1) -- Status = 1 means friendship accepted
OR (z.UserID = #userID AND z.Status = 1))
GROUP BY a.userID, a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate
ORDER BY Active DESC, DisplayName ASC
I am not sure how to clip in my execution plan but the main bottle neck seems to be occurring on a MERGE JOIN (Right Outer Join) that's costing me 29%. At various stages, Parallelism is also costing 9%, 6%, 5% and 9% for a total of 29% as well.
My initial thoughts are to first return the JOINED results from the Profile and aspnet tables with a CTE and then do LEFT JOINS to the Friends table.
You are joining Friend twice, using a LEFT JOIN, then you are removing the NULL's returned by the LEFT JOIN by WHERE condition, then using GROUP BY to get rid on distincts.
This is not the best query possible.
Why don't you just use this:
SELECT Active = CASE WHEN DATEDIFF("n", b.LastActivityDate ,GETDATE()) < #lastActivityMinutes THEN 1 ELSE 0 END,
a.DisplayName, a.ImageFile, a.UserId, b.LastActivityDate
FROM (
SELECT FriendID
FROM Friends
WHERE UserID = #UserId
AND status = 1
UNION
SELECT UserID
FROM Friends
WHERE FriendID = #UserId
AND status = 1
) x
INNER JOIN
Profile AS a
ON a.UserID = x.FriendID
INNER JOIN
aspnet_Users as b
ON b.userId = a.UserId
ORDER BY
Active DESC, DisplayName ASC

Resources