Pivot Values as Column Headers - sql-server

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

Related

Joining two big queries in sql

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.

How to place subquery in SQL Server 2008

I have a main SQL query which returns stock quantity in dates between and I also need to return the stock as on date along with between dates result.
Main query:
SELECT
TT.TranRId, MAX(TT.TInQty) AS InQty, MAX(TT.TOutQty) AS OutQty
FROM
TReg TR, TTrans TT
WHERE
TR.TRegId = TT.TrRegId
AND TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY
TT.TranRId
ORDER BY
TT.TranRId
Sub query:
(SELECT TT.TransRId, (SUM(TT.TInQty) - SUM(TT.TOutQty))
FROM TTrans TT, TReg TR
WHERE TR.TransDate <= '2018-08-24'
AND TR.TRegId = TT.TrRegId
AND TT.Stid = 2 GROUP BY TT.TranRId) --AS Stock
Please help where I should include my sub query in my main query
To get output as follows:
TransRId Stock InQty OutQty
----------------------------------
41 700 1 1000
42 800 5 500
I am not sure I am following your question 100%, if you are just looking to join it as a sub query the below logic should work.
SELECT TT.TranRId
,MAX(TT.TInQty) AS InQty
,MAX(TT.TOutQty) AS OutQty
,Stock.[Sum]
FROM TReg TR
LEFT JOIN TTrans TT
ON TR.TRegId = TT.TrRegId
LEFT JOIN (
SELECT TT.TransRId
,(SUM(TT.TInQty) - SUM(TT.TOutQty)) as Sum
FROM TTrans TT
LEFT JOIN TReg TR
ON TR.TRegId = TT.TrRegId
WHERE TR.TransDate <= '2018-08-24'
AND TT.Stid = 2
GROUP BY TT.TranRId
) AS Stock
ON Stock.TranRId = TT.TranRId
WHERE TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY TT.TranRId
ORDER BY TT.TranRId
edit:
I noticed tt.TranRId and tt.Tran***s***RId if this is not a typo it would need to be corrected, if not my answer will not work for you.
If you need specific dates, including the date in the join logic along with the ID would give you the appropriate result...without knowing your data set I am not sure if the TranRId is unique...sorry about that!

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

Is this the only way to filter the right table in a left outer join?

I have customer balances stored in their own table. the customer balances table gets a new set of records every day (reflecting the balance that day) but contains balances for other days (yyyy-mm-dd). I wanted to get all UK customers from accountinformation and their balances yesterday from balances. I wanted to include rows from accountinformation even where there is no corresponding record (for yesterday) in balances...
select firstname,lastname,accountnumber,balance from accountinformation i
left outer join balances b
on i.accountnumber = b.account
where country = 'UK' and status = 'OPEN'
and (b.date = '2014-04-10' or b.date is null)
... it did not satisfy the requirement to show rows from accountinformation if there is no corresponding row in balances. I had to write the query like this...
select firstname,lastname,accountnumber,balance from accountinformation i
left outer join (select * from balances where date = '2014-04-10') b
on i.accountnumber = b.account
where country = 'UK' and status = 'OPEN'
.. to get the desired behavour. In the interests of correctness I want to know if there is a more correct way to filter the left table in a left outer join?
you might be able to do
select firstname,lastname,accountnumber,balance from accountinformation i
left outer join balances b
on i.accountnumber = b.account and b.date = '2014-04-10'
where country = 'UK' and status = 'OPEN'

Resources