Use UNION ALL and GROUP BY to combine 3 TSQL statements into one query - tsql

I have 3 TSQL queries that work individually, but I need to combine them into one single query. In Microsoft Access, they were successfully combined using the following SQL statement; however, I am trying to reverse engineer all the data using TSQL. How can I do the same thing in TSQL? Keep in mind that ap.property_id and af1.property_id are from different tables.
SELECT property_id]
FROM [Insured (see TSQL Statement 1)]
GROUP BY property_id
UNION ALL
SELECT property_id
FROM [Uninsured (see TSQL Statement 2)]
GROUP BY property_id
UNION ALL
SELECT property_id
FROM [IE > 90 Days (see TSQL Statement 3)]
GROUP BY property_id;
TSQL Statement 1 (Insured)
SELECT
rtrim(STR_REPLACE(ap.region_name,' Region','')) AS 'Region',
ap.property_id,
ap.is_under_management_ind,
ap.is_insured_ind,
ap.has_active_assistance_ind,
af1.is_pipeline_ind,
CASE
WHEN ap.is_insured_ind = "Y" THEN "Insured"
ELSE "Other"
END AS 'Classification 1',
CASE
WHEN ap.is_insured_ind = "Y" AND ap.is_under_management_ind = "Y" AND af1.is_pipeline_ind = "N" THEN "Insured Only"
WHEN ap.is_insured_ind = "Y" AND ap.is_under_management_ind = "Y" AND af1.is_pipeline_ind = "Y" AND ap.has_active_assistance_ind = "Y" THEN "Insured and Assisted"
ELSE "Other Insured"
END AS 'Classification 2'
FROM rems_dmart.dbo.active_financing af1
INNER JOIN rems_dmart.dbo.active_property ap
ON af1.property_id = ap.property_id
GROUP BY
ap.region_name,
ap.property_id,
ap.is_under_management_ind,
ap.is_insured_ind,
ap.has_active_assistance_ind,
af1.is_pipeline_ind
HAVING
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "Y"
AND af1.is_pipeline_ind = "N" )
OR
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "Y"
AND af1.is_pipeline_ind = "Y"
AND ap.has_active_assistance_ind = "Y" )
TSQL Statement 2 (Uninsured)
SELECT
rtrim(STR_REPLACE(ap.region_name,' Region','')) AS 'Region',
ap.property_id,
ap.is_under_management_ind,
ap.is_insured_ind,
ap.has_use_restriction_ind,
ap.has_active_irp_ind,
ap.has_active_assistance_ind,
ap.is_service_coordinator_ind,
CASE
WHEN ap.is_insured_ind = "N" THEN "Uninsured"
ELSE "Other"
END AS 'Classification 1',
CASE
WHEN ap.is_insured_ind = "N" AND ap.has_active_assistance_ind = "Y" THEN "Assisted Only"
WHEN ap.is_insured_ind = "N" AND ap.has_active_assistance_ind = "N" AND ap.has_use_restriction_ind = "Y" THEN "Use Agreement Only"
WHEN ap.is_insured_ind = "N" AND ap.has_active_assistance_ind = "N" AND ap.has_use_restriction_ind = "N" AND ap.has_active_irp_ind = "Y" AND ap.is_service_coordinator_ind = "N" THEN "IRP"
WHEN ap.is_insured_ind = "N" AND ap.has_active_assistance_ind = "N" AND ap.has_use_restriction_ind = "N" AND ap.has_active_irp_ind = "N" AND ap.is_service_coordinator_ind = "Y" THEN "Service Coordinator"
WHEN ap.is_insured_ind = "N" AND ap.has_active_assistance_ind = "N" AND ap.has_use_restriction_ind = "N" AND ap.has_active_irp_ind = "Y" AND ap.is_service_coordinator_ind = "Y" THEN "IRP & Service Coordinator"
ELSE "Other Uninsured"
END AS 'Classification 2'
FROM rems_dmart.dbo.active_property ap
GROUP BY
ap.region_name,
ap.property_id,
ap.is_under_management_ind,
ap.is_insured_ind,
ap.has_use_restriction_ind,
ap.has_active_irp_ind,
ap.has_active_assistance_ind,
ap.is_service_coordinator_ind
HAVING
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "N"
AND ap.has_active_assistance_ind = "Y" )
OR
( ap.region_name <> "OHP"
AND ap.is_insured_ind = "N"
AND ap.has_use_restriction_ind = "Y" )
TSQL Statement 3 (IE > 90 Days)
SELECT
rtrim(STR_REPLACE(ap.region_name,' Region','')) AS 'Region',
af1.property_id,
af1.initial_endorsement_date,
af1.final_endorsement_date,
ap.is_under_management_ind,
CASE
WHEN af1.initial_endorsement_date IS NOT NULL AND af1.final_endorsement_date IS NULL THEN "IE > 90 Days"
ELSE "Other"
END AS 'Classification 1',
CASE
WHEN af1.initial_endorsement_date IS NOT NULL AND af1.final_endorsement_date IS NULL AND ap.is_under_management_ind = "Y" THEN "IE > 90 Days_Under Mgmt"
WHEN af1.initial_endorsement_date IS NOT NULL AND af1.final_endorsement_date IS NULL AND ap.is_under_management_ind = "N" THEN "IE > 90 Days_Not Under Mgmt"
ELSE "Other IE > 90 Days"
END AS 'Classification 2'
FROM rems_dmart.dbo.active_property ap
INNER JOIN rems_dmart.dbo.active_financing af1
ON ap.property_id = af1.property_id
WHERE
( ap.region_name <> "OHP"
AND DATEDIFF(DAY, af1.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90
AND af1.final_endorsement_date IS NULL
AND ap.is_under_management_ind = "N" )
OR
( ap.region_name <> "OHP"
AND DATEDIFF(DAY, af1.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90
AND af1.final_endorsement_date IS NULL
AND ap.is_under_management_ind = "Y" )

Here is an example of how you could combine three TSQL statements into one query using the UNION ALL operator and GROUP BY clause:
WITH CTE AS (
SELECT column1, column2, SUM(column3) as Total_Column3
FROM table1
WHERE column4 = 'value1'
GROUP BY column1, column2
UNION ALL
SELECT column1, column2, SUM(column3) as Total_Column3
FROM table2
WHERE column5 = 'value2'
GROUP BY column1, column2
UNION ALL
SELECT column1, column2, SUM(column3) as Total_Column3
FROM table3
WHERE column6 = 'value3'
GROUP BY column1, column2
)
SELECT column1, column2, SUM(Total_Column3) as Grand_Total
FROM CTE
GROUP BY column1, column2
This query creates a common table expression (CTE) from the results of three SELECT statements, each of which aggregates data from a different table and filters it based on a specific condition. The UNION ALL operator combines the results of these SELECT statements into a single result set. Finally, the query uses the GROUP BY clause to aggregate the Grand Total of Total_Column3 by column1 and column2.

Your code can be translated into
--1
SELECT
AP.property_id
FROM rems_dmart.dbo.active_financing AS AF
INNER JOIN rems_dmart.dbo.active_property AS AP
ON AF.property_id = AP.property_id
WHERE AP.region_name <> 'OHP' AND AP.is_under_management_ind = 'Y' AND AP.is_insured_ind = 'Y' AND AF.is_pipeline_ind = 'N'
UNION
--2
SELECT
property_id
FROM rems_dmart.dbo.active_property
WHERE region_name <> 'OHP' AND is_insured_ind = 'N' AND has_active_assistance_ind = 'Y'
UNION
--3
SELECT
AF.property_id
FROM rems_dmart.dbo.active_property AS AP
INNER JOIN rems_dmart.dbo.active_financing AS AF
ON AP.property_id = AF.property_id
WHERE AP.region_name <> 'OHP' AND DATEDIFF(DAY, AF.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90 AND AF.final_endorsement_date IS NULL AND AP.is_under_management_ind IN ('N','Y')
or even further to
SELECT
AP.property_id
FROM rems_dmart.dbo.active_financing AS AF
INNER JOIN rems_dmart.dbo.active_property AS AP
ON AF.property_id = AP.property_id
WHERE AP.region_name <> 'OHP' AND
(
(AP.is_under_management_ind = 'Y' AND AP.is_insured_ind = 'Y' AND AF.is_pipeline_ind = 'N')
OR
(DATEDIFF(DAY, AF.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90 AND AF.final_endorsement_date IS NULL AND AP.is_under_management_ind IN ('N','Y'))
)
UNION
SELECT
property_id
FROM rems_dmart.dbo.active_property
WHERE region_name <> 'OHP' AND is_insured_ind = 'N' AND has_active_assistance_ind = 'Y'
#john-bollinger said many good things for your query, so try to use his answer as well.
Also you need to have good indices on the two table for your query to run smooth.

In the first place, the final results you want are only the property_id values. A natural first step, then, would be to remove everything else from the select lists of (copies of) the TSQL queries. That already makes them much simpler.
In the second place, the first two original TSQL queries use GROUP BY but not any aggregate functions. They do include all the grouping columns in their select lists. This has one primary and at least one secondary effect:
the primary effect is de-duplication of the rows, equivalent to a select distinct
the secondary effect may be the real point: the filter conditions are applied via a having clause, such that (logically) they are are tested after row de-duplication.
However, if there are no duplicate property_id values in either of the two base tables then grouping and distinct selection in these two queries are both moot, as inclusion of one of the property_ids among the grouping columns means that there cannot be any groups with more than one row, nor would there be duplicate result rows in any case.
This suggests removing the GROUP BY clauses and converting the HAVING clauses to WHERE clauses.
In the third place, the three queries are all selecting from approximately the same join of the same two tables. The second is selecting from a single one of the tables, but since there are no duplicates in the join columns, we can make it effectively the same thing by converting the inner join to an outer one. Even that would be unnecessary if you could rely on every row in ap having a corresponding row in af1. Additionally, although you claim that they are selecting property_id columns from different tables, that's a technicality. Query 3 could be modified to select ap.property_id instead of af1.property_id without changing the results, because these are guaranteed to be equal in every row of the rowset.
Thus, these three queries can usefully be combined into a single one without relying on a union. They can be adjusted to be ordinary queries with the same select list and source row set, so all that remains is unifying the filter conditions. Before working on the filter condition, that's this:
-- can be made SELECT DISTINCT if duplicates are present after all:
SELECT ap.property_id
FROM rems_dmart.dbo.active_property ap
LEFT OUTER JOIN rems_dmart.dbo.active_financing af1
ON af1.property_id = ap.property_id
WHERE
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "Y"
AND af1.is_pipeline_ind = "N" )
OR
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "Y"
AND af1.is_pipeline_ind = "Y"
AND ap.has_active_assistance_ind = "Y" )
OR
( ap.region_name <> "OHP"
AND ap.is_under_management_ind = "Y"
AND ap.is_insured_ind = "N"
AND ap.has_active_assistance_ind = "Y" )
OR
( ap.region_name <> "OHP"
AND ap.is_insured_ind = "N"
AND ap.has_use_restriction_ind = "Y" )
OR
( ap.region_name <> "OHP"
AND DATEDIFF(DAY, af1.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90
AND af1.final_endorsement_date IS NULL
AND ap.is_under_management_ind = "N" )
OR
( ap.region_name <> "OHP"
AND DATEDIFF(DAY, af1.initial_endorsement_date, CONVERT(VARCHAR(20), GETDATE(), 101)) > 90
AND af1.final_endorsement_date IS NULL
AND ap.is_under_management_ind = "Y" )
Again, as long as there are no duplicate property_id values in either table, there is no need for a GROUP BY or a DISTINCT selection, but if you have to accommodate duplicates after all then you can just change the SELECT to SELECT DISTINCT.
That filter condition could be better factored, but at this point it's highly reflective of the original queries. That may make it easier to validate or check. I would consider at least lifting the condition on ap.region_name out of all the the individual alternatives, but I leave that and any other refactoring you want to perform to you.

Related

More than one row returned by a subquery used as an expressin

This works:
SELECT DISTINCT
"public".visit.visit_id,
"public".visit.visit_name,
"public".visit.visit_admit_date,
"public".visit.visit_disch_date,
"public".visit.visit_stay_type,
"public".visit.visit_ins,
"public".ip_visit_1.ipv1_room,
"public".ip_visit_1.ipv1_ad_init,
CASE WHEN (SELECT digital_signature_images.dsigimg_acct FROM digital_signature_images where "public".visit.visit_id = digital_signature_images.dsigimg_acct AND digital_signature_images.dsigimg_title = 'IMPORTANT LETTER FROM MEDICARE') IS NOT NULL THEN 'YES'
WHEN (SELECT patient_images.patimg_acct FROM patient_images where visit.visit_id = patient_images.patimg_acct AND patient_images.patimg_title = 'IMPORTANT LETTER FROM MEDICARE') IS NOT NULL THEN 'YES' ELSE 'NOT ON FILE' END AS IMFM_ON_FILE
FROM
"public".digital_signature_images
INNER JOIN "public".visit ON "public".visit.visit_id = "public".digital_signature_images.dsigimg_acct
INNER JOIN "public".ip_visit_1 ON "public".visit.visit_id = "public".ip_visit_1.ipv1_num
INNER JOIN "public".patient_images ON "public".patient_images.patimg_acct = "public".visit.visit_id
WHERE
"public".visit.visit_ins LIKE 'M%' AND
"public".visit.visit_stay_type = '1' AND
"public".visit.visit_disch_date = '2022-07-01'
ORDER BY
"public".ip_visit_1.ipv1_room
When I try to do the previous month only in the WHERE portion, I get told "More than one row returned by a subquery used as an expression:
SELECT DISTINCT
"public".visit.visit_id,
"public".visit.visit_name,
"public".visit.visit_admit_date,
"public".visit.visit_disch_date,
"public".visit.visit_stay_type,
"public".visit.visit_ins,
"public".ip_visit_1.ipv1_room,
"public".ip_visit_1.ipv1_ad_init,
CASE WHEN (SELECT digital_signature_images.dsigimg_acct FROM digital_signature_images where "public".visit.visit_id = digital_signature_images.dsigimg_acct AND digital_signature_images.dsigimg_title = 'IMPORTANT LETTER FROM MEDICARE') IS NOT NULL THEN 'YES'
WHEN (SELECT patient_images.patimg_acct FROM patient_images where visit.visit_id = patient_images.patimg_acct AND patient_images.patimg_title = 'IMPORTANT LETTER FROM MEDICARE') IS NOT NULL THEN 'YES' ELSE 'NOT ON FILE' END AS IMFM_ON_FILE
FROM
"public".digital_signature_images
INNER JOIN "public".visit ON "public".visit.visit_id = "public".digital_signature_images.dsigimg_acct
INNER JOIN "public".ip_visit_1 ON "public".visit.visit_id = "public".ip_visit_1.ipv1_num
INNER JOIN "public".patient_images ON "public".patient_images.patimg_acct = "public".visit.visit_id
WHERE
"public".visit.visit_ins LIKE 'M%' AND
"public".visit.visit_stay_type = '1' AND
ip_visit_1.ipv1_dis_date >= DATE_TRUNC('MONTH', CURRENT_DATE - INTERVAL '1 MONTH') AND
ip_visit_1.ipv1_dis_date < DATE_TRUNC('MONTH', CURRENT_DATE)
ORDER BY
"public".ip_visit_1.ipv1_room
How can I return the previous month?
use EXISTS (subquery) to determine if a subquery returns at least one row. It returns a boolean, so you can put it directly after the WHEN.

How to repeat some data points in query results?

I am trying to get the max date by account from 3 different tables and view those dates side by side. I created a separate query for each table, merged the results with UNION ALL, and then wrapped all that in a PIVOT.
The first 2 sections in the link/pic below show what I have been able to accomplish and the 3rd section is what I would like to do.
Query results by step
How can I get the results from 2 of the tables to repeat? Is that possible?
--define var_ent_type = 'ACOM'
--define var_ent_id = '52766'
--define var_dict_id = 113
SELECT
*
FROM
(
SELECT
E.ENTITY_TYPE,
E.ENTITY_ID,
'PERF_SUMMARY' as "TableName",
PS.DICTIONARY_ID,
to_char(MAX(PS.END_EFFECTIVE_DATE), 'YYYY-MM-DD') as "MaxDate"
FROM
RULESDBO.ENTITY E
INNER JOIN PERFORMDBO.PERF_SUMMARY PS ON (PS.ENTITY_ID = E.ENTITY_ID)
WHERE
1=1
-- AND E.ENTITY_TYPE = '&var_ent_type'
-- AND E.ENTITY_ID = '&var_ent_id'
AND PS.DICTIONARY_ID >= 100
AND (E.ACTIVE_STATUS <> 'N' )--and E.TERMINATION_DATE is null )
GROUP BY
E.ENTITY_TYPE,
E.ENTITY_ID,
'PERF_SUMMARY',
PS.DICTIONARY_ID
union all
SELECT
E.ENTITY_TYPE,
E.ENTITY_ID,
'POSITION' as "TableName",
0 as DICTIONARY_ID,
to_char(MAX(H.EFFECTIVE_DATE), 'YYYY-MM-DD') as "MaxDate"
FROM
RULESDBO.ENTITY E
INNER JOIN HOLDINGDBO.POSITION H ON (H.ENTITY_ID = E.ENTITY_ID)
WHERE
1=1
-- AND E.ENTITY_TYPE = '&var_ent_type'
-- AND E.ENTITY_ID = '&var_ent_id'
AND (E.ACTIVE_STATUS <> 'N' )--and E.TERMINATION_DATE is null )
GROUP BY
E.ENTITY_TYPE,
E.ENTITY_ID,
'POSITION',
1
union all
SELECT
E.ENTITY_TYPE,
E.ENTITY_ID,
'CASH_ACTIVITY' as "TableName",
0 as DICTIONARY_ID,
to_char(MAX(C.EFFECTIVE_DATE), 'YYYY-MM-DD') as "MaxDate"
FROM
RULESDBO.ENTITY E
INNER JOIN CASHDBO.CASH_ACTIVITY C ON (C.ENTITY_ID = E.ENTITY_ID)
WHERE
1=1
-- AND E.ENTITY_TYPE = '&var_ent_type'
-- AND E.ENTITY_ID = '&var_ent_id'
AND (E.ACTIVE_STATUS <> 'N' )--and E.TERMINATION_DATE is null )
GROUP BY
E.ENTITY_TYPE,
E.ENTITY_ID,
'CASH_ACTIVITY',
1
--ORDER BY
-- 2,3, 4
)
PIVOT
(
MAX("MaxDate")
FOR "TableName"
IN ('CASH_ACTIVITY', 'PERF_SUMMARY','POSITION')
)
Everything is possible. You only need a window function to make the value repeat across rows w/o data.
--Assuming current query is QC
With QC as (
...
)
select code, account, grouping,
--cash,
first_value(cash) over (partition by code, account order by grouping asc rows unbounded preceding) as cash_repeat,
perf,
--pos,
first_value(pos) over (partition by code, account order by grouping asc rows unbounded preceding) as pos_repeat
from QC
;
See first_value() help here: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/FIRST_VALUE.html#GUID-D454EC3F-370C-4C64-9B11-33FCB10D95EC

Unexpected "Subquery returned more than 1 value"

Tables have this structure: groupTable > lineGroupJoinTable > linesTable (name are obfuscated names)
I have the following query which returns this error:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
The thing is that I expect that since the subquery is group, I should not get this error. I'm probably missing something.
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT sumTable.fieldToSum FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.groupdId1, lgjt.groupdId2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.lineId1 = lt.lineId1 AND lgjt.lineId2 = lt.lineId2
GROUP BY lgjt.groupdId1, lgjt.groupdId2
) sumTable
ON sumTable.groupdId1 = gt.groupdId1 AND sumTable.groupdId2 = gt.groupdId2
)
END
This variation was also try following a suggestion but return the same error:
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT SUM(sumTable.fieldToSum) FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.groupdId1, lgjt.groupdId2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.lineId1 = lt.lineId1 AND lgjt.lineId2 = lt.lineId2
GROUP BY lgjt.groupdId1, lgjt.groupdId2
) sumTable
ON sumTable.groupdId1 = gt.groupdId1 AND sumTable.groupdId2 = gt.groupdId2
GROUP BY gt.groupdId1, gt.groupdId2
)
END
Probably because dbo.groupTable has multiple value for the combination id1 and id2. I suggest to group on the id1 and id2 column and do a SUM, that case you will have only 1 result.
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT SUM(sumTable.fieldToSum) FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.id1, lgjt.id2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.id3 = lt.id3 AND lgjt.id4 = lt.id4
GROUP BY lgjt.id1, lgjt.id2
) sumTable
ON sumTable.id1 = gt.id1 AND sumTable.id2 = gt.id2
GROUP BY gt.id1, gt.id2
)
END

Left Join with multiple criteria which are partly empty or null

I have a table with tracking data. Among other values the table has the columns traffic_medium, traffic_source and traffic_campaign. The columns do contain sometimes (none) or null as value.
I would like to match the sum of visitors from an other table using a left join with medium, scource and campaign as matching criteria.
This works fine if all columns contain data. It does not work, if one column has (none) or null as value.
I use BigQuery and legacy SQL.
SELECT
A.id,
A.trafficSource_medium,
A.trafficSource_source,
A.trafficSource_campaign,
B.sum_visitor AS sum_visitor
FROM [table] AS A
left outer join (Select
count(distinct fullvisitorID) as sum_visitor,
trafficSource_medium,
trafficSource_source,
trafficSource_campaign
FROM [table2]
GROUP BY trafficSource_medium,
trafficSource_source,
trafficSource_campaign)
AS B
on A.trafficSource_medium=B.trafficSource_medium AND
A.trafficSource_source=B.trafficSource_source AND
A.trafficSource_campaign=B.trafficSource_campaign
Thanks for your help!
Try something like below
Assuming respective fields are of STRING type. If they are INT - replace 'n/a' with let's say -999 - important to choose constant that is not used as a value for respective field
#legacySQL
SELECT
A.id,
CASE WHEN A.trafficSource_medium = 'n/a' THEN NULL ELSE A.trafficSource_medium END AS trafficSource_medium,
CASE WHEN A.trafficSource_source = 'n/a' THEN NULL ELSE A.trafficSource_source END AS trafficSource_source,
CASE WHEN A.trafficSource_campaign = 'n/a' THEN NULL ELSE A.trafficSource_campaign END AS trafficSource_campaign,
B.sum_visitor AS sum_visitor
FROM (
SELECT
id,
IFNULL(trafficSource_medium, 'n/a') AS trafficSource_medium,
IFNULL(trafficSource_source, 'n/a') AS trafficSource_source,
IFNULL(trafficSource_campaign 'n/a') AS trafficSource_campaign
FROM [table]
) AS A
LEFT OUTER JOIN (
SELECT
COUNT(DISTINCT fullvisitorID) AS sum_visitor,
IFNULL(trafficSource_medium, 'n/a') AS trafficSource_medium,
IFNULL(trafficSource_source, 'n/a') AS trafficSource_source,
IFNULL(trafficSource_campaign 'n/a') AS trafficSource_campaign
FROM [table2]
GROUP BY
trafficSource_medium,
trafficSource_source,
trafficSource_campaign
) AS B
ON A.trafficSource_medium = B.trafficSource_medium
AND A.trafficSource_source = B.trafficSource_source
AND A.trafficSource_campaign = B.trafficSource_campaign
Idea here is to "transform" NULLs to some value so they are JOIN'able - and then "transform" it back to NULL in final SELECT
If you can migrate to Standard SQL - you can try below instead - it is less changes to do - just mostly in ON clause
#standardSQL
SELECT
A.id,
A.trafficSource_medium,
A.trafficSource_source,
A.trafficSource_campaign,
B.sum_visitor AS sum_visitor
FROM `table` AS A
LEFT OUTER JOIN (
SELECT
COUNT(DISTINCT fullvisitorID) AS sum_visitor,
trafficSource_medium,
trafficSource_source,
trafficSource_campaign
FROM `table2`
GROUP BY
trafficSource_medium,
trafficSource_source,
trafficSource_campaign
) AS B
ON IFNULL(A.trafficSource_medium, 'n/a') = IFNULL(B.trafficSource_medium, 'n/a')
AND IFNULL(A.trafficSource_source, 'n/a') = IFNULL(B.trafficSource_source, 'n/a')
AND IFNULL(A.trafficSource_campaign, 'n/a') = IFNULL(B.trafficSource_campaign, 'n/a')

set value from select for few select

I have select, iside select have 2 column. This column must be filled from same select, but I don't want use select twice for it. Is it possoble use select 1 time and after that set second column value from first?
Example:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = (select aa from table1 where quantity > 5)
I need:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = {value from a}
Update. I wrote bad example, I need set to BalancePrediction1 and BalancePrediction2 value from Balance
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance -
(
SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
)
) as Balance,
Balance AS 'BalancePrediction1',
Balance AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
You could do an update to the table variable after the insert.
update #tmpBalances
set BalancePrediction1 = Balance,
BalancePrediction2 = Balance
Or you can use cross apply to calculate the sum.
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance - Mov.SumAmount) AS Balance,
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction1',
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
CROSS APPLY (SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
) Mov(SumAmount)
SELECT aa AS a, aa AS b
FROM table1
WHERE quantity > 5
One way;
;with T (value) as (
select aa from table1 where quantity > 5
)
insert into #temptable
select value, value from T