SQL, How to use temp table and join multiple table - sql

Actually, I am using GridView at vb.net. this is the sql in the datasource.
SELECT SE.shipperID
, SE.sName
, SE.consigneeID
, SE.conName
, SE.agentID
, SE.aName
, SEDetail.bolId
, SE.masterBOLno
, SE.coloaderBOLno
, SE.NumOBOL
, SE.polName
, SE.podName
, CONVERT(VARCHAR ,SE.onboardDate ,111)
, SUM(SEDetail.quantity)
, SUM(SEDetail.totalSize)
, SUM(SEDetail.totalWeight)
FROM SE
INNER JOIN SEDetail ON SE.id = SEDetail.bolId
WHERE SE.id = SEDetail.bolId
GROUP BY SE.shipperID, SE.sName, SE.consigneeID, SE.conName, SE.agentID,
SE.aName, SE.masterBOLno, SE.coloaderBOLno, SE.NumOBOL, SEDetail.bolId,
SE.polName, SE.podName, SE.onboardDate
I want use the TemplateField to add 3 column , but GridView can not use multiple datasource
column 1. count(SEDetail.containerId) (where b.SEDetail.containerId between 1 and 5 )
column 2. count(SEDetail.containerId) (where b.SEDetail.containerId between 6 and 10 )
column 3. count(SEDetail.containerId) (where b.SEDetail.containerId = 11 )
So, how to use the temp table or another way to group up to one statement.

Not sure what flavor of SQL you are using but could you not add the following to your select statement:
SUM(CASE WHEN b.SEDetail.containerId BETWEEN 1 AND 5
THEN 1 ELSE 0 END) AS column1
SUM(CASE WHEN b.SEDetail.containerId BETWEEN 6 AND 10
THEN 1 ELSE 0 END) AS column2
SUM(CASE WHEN b.SEDetail.containerId = 11
THEN 1 ELSE 0 END) AS column3

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

Sum a column and perform more calculations on the result? [duplicate]

This question already has an answer here:
How to use an Alias in a Calculation for Another Field
(1 answer)
Closed 3 years ago.
In my query below I am counting occurrences in a table based on the Status column. I also want to perform calculations based on the counts I am returning. For example, let's say I want to add 100 to the Snoozed value... how do I do this? Below is what I thought would do it:
SELECT
pu.ID Id, pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed,
Snoozed + 100 AS Test
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
I get this error:
Invalid column name 'Snoozed'.
How can I take the value of the previous SUM statement, add 100 to it, and return it as another column? What I was aiming for is an additional column labeled Test that has the Snooze count + 100.
You can't use one column to create another column in the same way that you are attempting. You have 2 options:
Do the full calculation (as #forpas has mentioned in the comments above)
Use a temp table or table variable to store the data, this way you can get the first 5 columns, and then you can add the last column or you can select from the temp table and do the last column calculations from there.
You can not use an alias as a column reference in the same query. The correct script is:
SELECT
pu.ID Id, pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END)+100 AS Snoozed
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
MSSQL does not allow you to reference fields (or aliases) in the SELECT statement from within the same SELECT statement.
To work around this:
Use a CTE. Define the columns you want to select from in the CTE, and then select from them outside the CTE.
;WITH OurCte AS (
SELECT
5 + 5 - 3 AS OurInitialValue
)
SELECT
OurInitialValue / 2 AS OurFinalValue
FROM OurCte
Use a temp table. This is very similar in functionality to using a CTE, however, it does have different performance implications.
SELECT
5 + 5 - 3 AS OurInitialValue
INTO #OurTempTable
SELECT
OurInitialValue / 2 AS OurFinalValue
FROM #OurTempTable
Use a subquery. This tends to be more difficult to read than the above. I'm not certain what the advantage is to this - maybe someone in the comments can enlighten me.
SELECT
5 + 5 - 3 AS OurInitialValue
FROM (
SELECT
OurInitialValue / 2 AS OurFinalValue
) OurSubquery
Embed your calculations. opinion warning This is really sloppy, and not a great approach as you end up having to duplicate code, and can easily throw columns out-of-sync if you update the calculation in one location and not the other.
SELECT
5 + 5 - 3 AS OurInitialValue
, (5 + 5 - 3) / 2 AS OurFinalValue
You can't use a column alias in the same select. The column alias do not precedence / sequence; they are all created after the eval of the select result, just before group by and order by.
You must repeat code :
SELECT
pu.ID Id,pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END)+ 100 AS Test
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
If you don't want to repeat the code, use a subquery
SELECT
ID, Name, LeadCount, Working, Uninterested,Converted, Snoozed, Snoozed +100 AS test
FROM
(SELECT
pu.ID Id,pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed
FROM Prospects p
INNER JOIN ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE p.Store = '108'
GROUP BY pu.Name, pu.Id) t
ORDER BY Name
or a view

Count rows for two columns using two different clauses

I'm after a CTE which I want to return two columns, one with the total number of 1's and one with the total number of 0's. Currently I can get it to return one column with the total number of 1's using:
WITH getOnesAndZerosCTE
AS (
SELECT COUNT([message]) AS TotalNo1s
FROM dbo.post
WHERE dbo.checkletters([message]) = 1
--SELECT COUNT([message]) AS TotalNo0s
--FROM dbo.post
--WHERE dbo.checkletters([message]) = 0
)
SELECT * FROM getOnesAndZerosCTE;
How do I have a second column called TotalNo0s in the same CTE which I have commented in there to show what I mean.
Using conditional aggregation:
WITH getOnesAndZerosCTE AS(
SELECT
TotalNo1s = SUM(CASE WHEN dbo.checkletters([message]) = 1 THEN 1 ELSE 0 END),
TotalNo0s = SUM(CASE WHEN dbo.checkletters([message]) = 0 THEN 1 ELSE 0 END)
FROM post
)
SELECT * FROM getOnesAndZerosCTE;
For using COUNT() directly just be aware that it counts any NON-NULL values. You can omit the ELSE condition which implicitly returns NULL if not stated
SELECT
COUNT(CASE WHEN dbo.checkletters([message]) = 1 THEN 1 END) TotalNo1s
, COUNT(CASE WHEN dbo.checkletters([message]) = 0 THEN 1 END) TotalNo0s
FROM post
or, explicitly state NULL
SELECT
COUNT(CASE WHEN dbo.checkletters([message]) = 1 THEN 1 ELSE NULL END) TotalNo1s
, COUNT(CASE WHEN dbo.checkletters([message]) = 0 THEN 1 ELSE NULL END) TotalNo0s
FROM post
You can do it without CTE
select count(message) total,
dbo.checkletters(message) strLength
from post
group by dbo.checkletters(message)
having dbo.checkletters(message) in (1, 2) //All the messages with length 1 or 2

Joining two tables and while pivoting sql server 2008

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

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.