Joining two tables and while pivoting sql server 2008 - sql

I have two tables like so
Table1
SegmentNo PassingPotencies
1 8
2 10
Table2
BatchAvg Total TotalSegments TotalPassed
106.22 20 2 18
I want to join two tables with a simple login. If the Passingpotencies in table 1 is not equal to 10 then the segment is failed and vice versa. The final result should look something like this
TableResult
BatchAvg Total TotalSegments TotalPassed Segment1 Segment2
106.22 20 2 18 Fail Pass
Any help is greatly appreciated. Thanks.

With your current design, this is what you can achieve (something closest).
See a demo here http://sqlfiddle.com/#!3/e86f5/5
select distinct BATCHAVG,
TOTAL,
TOTALSEGMENTS,
TOTALPASSED,
SegmentNo,
case when PASSINGPOTENCIES <> 10 then 'Failed'
else 'Passed' end as SegmentStatus
from
(
select * from table2,table1
) X
Above query will results in

This will work in your actual scenario. See a Demo here: SQLFiddle
First, join both tables:
SELECT
T2.BATCHAVG
, T2.TOTAL
, T2.TOTALSEGMENTS
, T2.TOTALPASSED
, T1.SEGMENTNO
, (CASE WHEN T1.PASSINGPOTENCIES >= 10 THEN 'PASSED' ELSE 'FAILED' END) AS SEGMENT
INTO TABLE3
FROM TABLE1 T1
CROSS JOIN TABLE2 T2
Then, select this table like this. It's some kind of PIVOT:
SELECT
T.BATCHAVG
, T.TOTAL
, T.TOTALSEGMENTS
, T.TOTALPASSED
, MAX(T.SEGMENT1) AS SEGMENT1
, MAX(T.SEGMENT2) AS SEGMENT2
FROM (
SELECT
T1.BATCHAVG
, T1.TOTAL
, T1.TOTALSEGMENTS
, T1.TOTALPASSED
, (CASE WHEN T1.SEGMENTNO = '1' THEN T1.SEGMENT END) AS SEGMENT1
, (CASE WHEN T1.SEGMENTNO = '2' THEN T1.SEGMENT END) AS SEGMENT2
FROM TABLE3 T1
) T
GROUP BY
T.BATCHAVG
, T.TOTAL
, T.TOTALSEGMENTS
, T.TOTALPASSED

Related

Get single row depending of conditional

I have a simple select query with some joins like:
SELECT
[c].[column1]
, [c].[column2]
FROM [Customer] AS [c]
INNER JOIN ...
So I do a left join with my principal table as:
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
this relatioship its 1 to *, one customer can have multiple communications
So in my select I want to get value 1 or 2 depending of condition:
Condition:
if ComTypeKey (from communication) table have a row with value 3 and have another row with vale 4 return 1 then 0
So I try something like:
SELECT
[c].[column1]
, [c].[column2]
, IIF([com].[ComTypeKey] = 3 AND [com].[ComTypeKey] = 4,1,0)
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
But it throws me two rows, beacause there are 2 rows on communication. My desire value is to get only one row with value 1 if my condition is true
If you have multiple rows you need GROUP BY, then count the relevant keys and subtract 1 to get (1, 0)
SELECT
[c].[column1]
, [c].[column2]
, COUNT(CASE WHEN [ComTypeKey] IN (3,4) THEN 1 END) - 1 as FLAG_CONDITION
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com]
ON [c].[CustomerGuid] = [com].[ComGuid]
GROUP BY
[c].[column1]
, [c].[column2]
I'm not really sure I understand.
This will literally find if both values 3 and 4 exist for that CustomerGuid, and only select one of them in that case - not filtering out any record otherwise.
If this is not what you want, providing sample data with the expected result would remove the ambiguity.
SELECT Field1,
Field2,
...
FieldN
FROM (SELECT TMP.*,
CASE WHEN hasBothValues = 1 THEN
ROW_NUMBER() OVER ( PARTITION BY CustomerGuid ORDER BY 1 )
ELSE 1
END AS iterim_rn
FROM (SELECT TD.*,
MAX(CASE WHEN Value1 = '3' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) *
MAX(CASE WHEN Value1 = '4' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) AS hasBothValues
FROM TEST_DATA TD
) TMP
) TMP2
WHERE interim_rn = 1

SQL Server Pivoting based off of a column to be delimited

I'm using SQL Server Management Studio and I have a table of survey results for project managers and I'm aggregating by question/score at the project manager RepID level:
SELECT Lower(A.RepID) as 'HHRepID'
, YEAR(A.ProjectEndDate) AS 'Year'
, MONTH(A.ProjectEndDate) AS 'Month'
, DATENAME(mm,A.ProjectEndDate) AS 'MonthName'
, SUM(CASE WHEN A.SatisfactionWithCommunication >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeCommunicationCount'
, COUNT(A.SatisfactionWithCommunication) as 'CommunicationCount'
, SUM(CASE WHEN A.InteractionConnectionWithClient >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeInteractionCount'
, COUNT(A.InteractionConnectionWithClient) as 'InteractionCount'
, SUM(CASE WHEN A.OverallSatisfactionWithEngagement >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeOverallSatisfactionCount'
, COUNT(A.OverallSatisfactionWithEngagement) as 'OverallSatisfactionCount'
, COUNT(A.ResponseID) as 'SurveysReturned'
, 'SalesOps' as 'Grouping'
FROM
SurveyData.dbo.SalesSurvey as A with(nolock)
WHERE
A.ResponseID IS NOT NULL AND A.IsExcludedFromReporting IS NULL
GROUP BY
YEAR(A.ProjectEndDate), MONTH(A.ProjectEndDate), DATENAME(mm,A.ProjectEndDate), A.RepID
ORDER BY
A.RepID
The output would look something like this:
Everything is great. Here's the problem. For each response for a project manager, there could be multiple Project Assistants. The project assistants for each project are aggregated (separated by ;) in one column:
What I need to do is pivot/delimit these results so each projectassistantID will be 1 row with the same grouped data as if it was a project manager. So for example, let's say that that row from the first screenshot had (HHRepID = jdoe) had 2 project assistants to it (call them Michael Matthews and Sarah Boyd): mmathews; sboyd. Via pivot/delimit, the output of the 2nd query would look like this:
In the actual table, it's just 1 record. But b/c there're multiple names in the ProjectAssistantID column, I need to pivot/delimit those out and essentially get the same results for each instance, just with ProjectAssistants rather than Project Managers.
I've been able to find some stuff on pivoting but this is pivoting based on delimiting values which adds an extra layer of complexity. It's entirely possible that there could be only 1 project assistant per project or as many as 6.
You can find several string split functions when you google for that, I will just assume this one which returns a table with one column named Item.
Then you can use cross apply as follows:
SELECT assist.Item as 'HHRepID'
, YEAR(A.ProjectEndDate) AS 'Year'
, MONTH(A.ProjectEndDate) AS 'Month'
, DATENAME(mm,A.ProjectEndDate) AS 'MonthName'
, SUM(CASE WHEN A.SatisfactionWithCommunication >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeCommunicationCount'
, COUNT(A.SatisfactionWithCommunication) as 'CommunicationCount'
, SUM(CASE WHEN A.InteractionConnectionWithClient >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeInteractionCount'
, COUNT(A.InteractionConnectionWithClient) as 'InteractionCount'
, SUM(CASE WHEN A.OverallSatisfactionWithEngagement >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeOverallSatisfactionCount'
, COUNT(A.OverallSatisfactionWithEngagement) as 'OverallSatisfactionCount'
, COUNT(A.ResponseID) as 'SurveysReturned'
, 'SalesOps' as 'Grouping'
FROM
SurveyData.dbo.SalesSurvey as A with(nolock)
CROSS APPLY Split(Lower(A.RepID), ';') AS assist
WHERE
A.ResponseID IS NOT NULL AND A.IsExcludedFromReporting IS NULL
GROUP BY
YEAR(A.ProjectEndDate), MONTH(A.ProjectEndDate), DATENAME(mm,A.ProjectEndDate), assist.Item
ORDER BY
assist.Item
For a strictly sql solution, you could use recursive cte to get your names split and then join it back to you query..
Try the below query
DECLARE #col varchar(20)='a;b;c;g;y;u;i;o;p;';
WITH CTE as
(
SELECT SUBSTRING(#COL,CHARINDEX(';',#COL)+1, LEN(#COL)-CHARINDEX(';', #COL)) col
,SUBSTRING(#COL,0, CHARINDEX(';',#COL)) Split_Names
, 1 i
union ALL
SELECT SUBSTRING(COL,CHARINDEX(';',COL)+1, LEN(COL)-CHARINDEX(';', COL)) col
,SUBSTRING(COL,0, CHARINDEX(';',COL)) Split_Names
, i+1
from CTE
WHERE CHARINDEX(';', col)>1
)
SELECT * FROM CTE
You will need to use your column in place of #col and change the code to refer to your table in the first union statement.
Hope this helps...
So you would do something like this...
WITH ProjectAssistants as
(
SELECT SUBSTRING(PROJECTASSISTANTID,CHARINDEX(';',PROJECTASSISTANTID)+1, LEN(PROJECTASSISTANTID)-CHARINDEX(';', PROJECTASSISTANTID)) col
,SUBSTRING(PROJECTASSISTANTID,0, CHARINDEX(';',PROJECTASSISTANTID)) Assistnames_Names
, ProjectManagerID
FROM YOUR_PROJECT_ASSISTANT_TABLE_NAME
union ALL
SELECT SUBSTRING(COL,CHARINDEX(';',COL)+1, LEN(COL)-CHARINDEX(';', COL)) col
,SUBSTRING(COL,0, CHARINDEX(';',COL)) Assistnames_Names
, ProjectManagerID
from ProjectAssistants
WHERE CHARINDEX(';', col)>1
)
SELECT Lower(A.RepID) as 'HHRepID'
, YEAR(A.ProjectEndDate) AS 'Year'
, MONTH(A.ProjectEndDate) AS 'Month'
, DATENAME(mm,A.ProjectEndDate) AS 'MonthName'
, SUM(CASE WHEN A.SatisfactionWithCommunication >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeCommunicationCount'
, COUNT(A.SatisfactionWithCommunication) as 'CommunicationCount'
, SUM(CASE WHEN A.InteractionConnectionWithClient >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeInteractionCount'
, COUNT(A.InteractionConnectionWithClient) as 'InteractionCount'
, SUM(CASE WHEN A.OverallSatisfactionWithEngagement >= 4 THEN 1 ELSE 0 END) as 'AgreeStronglyAgreeOverallSatisfactionCount'
, COUNT(A.OverallSatisfactionWithEngagement) as 'OverallSatisfactionCount'
, COUNT(A.ResponseID) as 'SurveysReturned'
, 'SalesOps' as 'Grouping'
FROM
SurveyData.dbo.SalesSurvey as A with(nolock)
LEFT JOIN ProjectAssistants as B
ON A.ProjectManagerID=B.ProjectManagerID
WHERE
A.ResponseID IS NOT NULL AND A.IsExcludedFromReporting IS NULL
GROUP BY
YEAR(A.ProjectEndDate), MONTH(A.ProjectEndDate), DATENAME(mm,A.ProjectEndDate), A.RepID
ORDER BY
A.RepID
Assumptions:
Your Surveydata table has a ProjectManagerid column
Left Join-ed the ProjectManager CTE considering you still want to show data when there arent any assistants.

SQL Aggreate Functions

I have table which list a number of cases and assigned primary and secondary technicians. What I am trying to accomplish is to aggregate the number of cases a technician has worked as a primary and secondary tech. Should look something like this...
Technician Primary Secondary
John 4 3
Stacy 3 1
Michael 5 3
The table that I am pulling that data from looks like this:
CaseID, PrimaryTech, SecondaryTech, DOS
In the past I have used something like this, but now my superiors are asking for the number of secondary cases as well...
SELECT PrimaryTech, COUNT(CaseID) as Total
GROUP BY PrimaryTech
I've done a bit of searching, but cant seem to find the answer to my problem.
Select Tech,
sum(case when IsPrimary = 1 then 1 else 0 end) as PrimaryCount,
sum(case when IsPrimary = 0 then 1 else 0 end) as SecondaryCount
from
(
SELECT SecondaryTech as Tech, 0 as IsPrimary
FROM your_table
union all
SELECT PrimaryTech as Tech, 1 as IsPrimary
FROM your_table
) x
GROUP BY Tech
You can group two subqueries together with a FULL JOIN as demonstrated in this SQLFiddle.
SELECT Technician = COALESCE(pri.Technician, sec.Technician)
, PrimaryTech
, SecondaryTech
FROM
(SELECT Technician = PrimaryTech
, PrimaryTech = COUNT(*)
FROM Cases
WHERE PrimaryTech IS NOT NULL
GROUP BY PrimaryTech) pri
FULL JOIN
(SELECT Technician = SecondaryTech
, SecondaryTech = COUNT(*)
FROM Cases
WHERE SecondaryTech IS NOT NULL
GROUP BY SecondaryTech) sec
ON pri.Technician = sec.Technician
ORDER By Technician;
SELECT COALESCE(A.NAME, B.NAME) AS NAME, CASE WHEN A.CASES IS NOT NULL THEN A.CASES ELSE 0 END AS PRIMARY_CASES,
CASE WHEN B.CASES IS NOT NULL THEN B.CASES ELSE 0 END AS SECONDARY_CASES
FROM
(
SELECT COUNT(*) AS CASES, PRIMARYTECH AS NAME FROM YOUR_TABLE
GROUP BY PRIMARYTECH
) AS A
FULL OUTER JOIN
(
SELECT COUNT(*) AS CASES, SECONDARYTECH AS NAME FROM YOUR_TABLE
GROUP BY SECONDARYTECH
) AS B
ON A.NAME = B.NAME

Select Distinct Attribute and Print out Count of another even when the count is 0

I don't quite know how I should describe the problem for title, but here's my question.
I have a table named hello with two columns named time and state.
Time | State
Here's an example of the data I have
1 DC
1 VA
1 VA
2 DC
2 MD
3 MD
3 MD
3 VA
3 DC
I would like to get all the possible time and the count of "VA" (0 if "VA" doesn't appear at the time)
The output would look like this
Time Number
1 2
2 0
3 1
I tried to do
SELECT DISTINCT time,
COUNT(state) as Number
FROM hello
WHERE state = 'VA'
GROUP BY time
but it doesn't seem to work.
This is a conditional aggregation:
select time, sum(case when state = 'VA' then 1 else 0 end) as NumVA
from hello
group by time
I want to add that you should never use distinct when you have a group by. The two are redundant. Distinct as a keyword is not even needed in the SQL language; semantically, it is just shorthand for grouping by all the columns.
SELECT TIME,
SUM(CASE WHEN State = 'VA' THEN 1 ELSE 0 END)
FROm tableName
GROUP BY Time
SQLFiddle Demo
One rule of thumb is to get your counts first and put them into a temp for use later.
See below:
Create table temp(Num int, [state] varchar(2))
Insert into temp(Num,[state])
Select 1,'DC'
UNION ALL
Select 1,'VA'
UNION ALL
Select 1,'VA'
UNION ALL
Select 2,'DC'
UNION ALL
Select 2,'MD'
UNION ALL
Select 3,'MD'
UNION All
Select 3,'MD'
UNION ALL
Select 3,'VA'
UNION ALL
Select 3,'DC'
Select t.Num [Time],t.[State]
, CASE WHEN t.[state] = 'VA' THEN Count(t.[State]) ELSE 0 END [Number]
INTO #temp2
From temp t
Group by t.Num, t.[state]
--drop table #temp2
Select
t2.[time]
,SUM(t2.[Number])
From #temp2 t2
group by t2.[time]

sql query group

SQL query question
I have a query like
select proposal_id, service_id,account_type
from table1
The result is like this:
proposal_id service_id account_type
1 1001 INTERVAL
1 1002 INTERVAL
2 1003 NON INTERVAL
2 1004 NON INTERVAL
3 1005 NON INTERVAL
3 1006 INTERVAL
I want to write a query: for each proposal_id, if all the service have INTERVAL then get 'INTERVAL', if all NON-INTERVAL get 'NON-INTERVAL', if both, get 'Both'
For the example above, it should return
proposal_id account_type
1 INTERVAL
2 NON-INTERVAL
3 BOTH
Data:
declare #table table (id int, sid int, acc nvarchar(20))
insert #table VALUES (1,1001,'INTERVAL'),(1,1002,'INTERVAL'),(2,1003,'NON INTERVAL'),(2,1004,'NON INTERVAL'),
(3,1005,'NON INTERVAL'),(3,1006,'INTERVAL')
Query:
select x.Id
, CASE counter
WHEN 1 THEN x.Account_Type
ELSE 'BOTH'
END AS Account_Type
from (
select Id, Count(DISTINCT(acc)) AS counter, MAX(acc) As Account_Type
from #table
GROUP BY Id
) x
Results
Id Account_Type
----------- --------------------
1 INTERVAL
2 NON INTERVAL
3 BOTH
SELECT
b.proposal_id
,CASE
WHEN s1.proposal_id IS NOT NULL AND s2.proposal_id IS NOT NULL THEN 'BOTH'
WHEN s1.proposal_id IS NOT NULL THEN 'INTERVAL'
WHEN s2.proposal_id IS NOT NULL THEN 'NON-INTERVAL'
ELSE 'UNKNOWN'
END [account_type]
FROM table1 b
LEFT JOIN(
SELECT proposal_id,account_type FROM table1 WHERE account_type = 'INTERVAL'
) s1
ON b.proposal_id = s1.proposal_id
LEFT JOIN (
SELECT proposal_id,account_type FROM table1 WHERE account_type = 'NON-INTERVAL'
)s2
ON b.proposal_id = s2.proposal_id
You could use count distinct to determinate if it is both then use CASE to determinate what to display
SELECT DISTINCT proposal.proposal_id,
CASE cou
WHEN 1 THEN type ELSE 'Both' END as TYPE
FROM proposal
INNER JOIN (SELECT proposal_id, count(distinct type) cou
FROM proposal GROUP BY proposal_id) inn
ON proposal.id = inn.id
select proposal_id,
case when count(distinct account_type) > 1 then 'BOTH'
else max(account_type)
end
from table1
group by proposal_id
You have the fiddler here.