Query works as expected, SSRS finds error? - sql-server

This question was closed because someone thought it was the same issue as SSRS multi-value parameter using a stored procedure
But it is not. My report is not a stored procedure and thus, behaves differently. Also, this issue describes a result of getting no results if multi-valued params are used and that too is inaccurate for this scenario. So I'll try posting this again.
My report for the most part works. It is when I select more than one value from either of 2 specific params (#global, #manual) that I get this error:
Here is the SQL:
DECLARE #STATE VARCHAR(2) = 'mn'
,#START DATE = '6/1/2020'
,#END DATE = '7/1/2020'
,#GLOBAL VARCHAR(50) = 'indigent fee'
,#MANUAL VARCHAR(100) = '''misc charges'',''discount'''
DROP TABLE
IF EXISTS #customers
,#test
SELECT DISTINCT ch.amount
,ch.vehicle_program_id
,c.customer_id
,ch.customer_charge_id
,ch.charge_type
INTO #customers
FROM customer c
JOIN customer_charge ch(NOLOCK) ON c.customer_id = ch.customer_id
JOIN service_history sh(NOLOCK) ON sh.customer_id = c.customer_id
JOIN header h(NOLOCK) ON h.service_history_id = sh.service_history_id
WHERE ch.entry_date BETWEEN #START
AND #END
AND ch.price_trigger_id IN (
16
,15
)
AND ch.source_type = 1
AND sh.service_type = 5
AND h.is_duplicate = 0;
WITH CTE_global
AS (
SELECT DISTINCT ch.charge_type
,'global' AS type
FROM customer_charge ch
JOIN store s ON ch.store_id = s.store_id
JOIN address a ON a.id = s.address_id
JOIN locality l ON a.locality_id = l.id
WHERE l.region = #state
AND ch.price_trigger_id = 16
UNION ALL
SELECT 'None'
,'global'
)
,CTE_manual
AS (
SELECT DISTINCT ch.charge_type
,'manual' AS type
FROM customer_charge ch
JOIN store s ON ch.store_id = s.store_id
JOIN address a ON a.id = s.address_id
JOIN locality l ON a.locality_id = l.id
WHERE l.region = #state
AND ch.price_trigger_id = 15
UNION ALL
SELECT 'None'
,'manual'
)
SELECT DISTINCT c.last_name
,c.first_name
,vp.account_no
,cust.charge_type
,cust.amount
,sh.service_date
,s.store_name_short
,GLOBAL = g.charge_type
,manual = m.charge_type
INTO #test
FROM vehicle_program vp(NOLOCK)
JOIN vehicle v(NOLOCK) ON v.vehicle_id = vp.vehicle_id
JOIN service_history sh(NOLOCK) ON sh.vehicle_program_id = vp.program_id
AND service_type = 5
JOIN customer c(NOLOCK) ON v.customer_id = c.customer_id
AND c.customer_id = sh.customer_id
JOIN store s(NOLOCK) ON vp.current_store_id = s.store_id
JOIN #customers cust ON cust.customer_id = c.customer_id
AND cust.vehicle_program_id = sh.vehicle_program_id
JOIN customer_condition cc(NOLOCK) ON c.customer_id = cc.customer_id
JOIN customer_charge ch(NOLOCK) ON ch.customer_id = c.customer_id
JOIN service_charge sc ON sc.service_history_id = sh.service_history_id
AND sc.customer_charge_id = cust.customer_charge_id
JOIN header h(NOLOCK) ON h.service_history_id = sh.service_history_id
JOIN CTE_global g ON g.charge_type = ch.charge_type
JOIN CTE_manual m ON m.charge_type = ch.charge_type
WHERE cc.state_of_conviction = #state
AND sh.service_date BETWEEN #START
AND #END
AND h.is_duplicate = 0
SELECT *
FROM #test
WHERE GLOBAL IN (
CASE
WHEN #global IN ('None')
THEN charge_type
WHEN #global NOT IN ('None')
THEN #global
END
)
OR manual IN (
CASE
WHEN #manual IN ('None')
THEN charge_type
WHEN #manual NOT IN ('None')
THEN #manual
END
)
For clarity, the last bit in the query there is some logic to allow for these two params to be optional: so by selecting 'None' that param is rendered useless basically. It seems clear that the issue is with this last bit, specifically my WHERE clause using the CASE expression. When I remove that, I don't get the error, but I of course lose my logic. What's most confusing is that the error indicates an issue with a comma, but there's no comma in that part of the SQL?? Any help is going to be greatly appreciated.

Assuming users will only select 'None' from the list on it's own and never with another value then the following should work.
WHERE (GLOBAL IN (#Global) OR #Global = 'None')
AND
(manual IN (#manual) OR #manual = 'None')

this question was closed because someone thought it was the same issue
It is a dupe, but you kind of have to read between the lines in the other answers to apply it to this scenario. The point is that SSRS replaces multi-select parameters with delimited strings in the query body itself, and this transformation can lead either to unexpectedly getting no results, or in an illegal SQL query, depending on where the parameter marker appears in the original query.
I'll make it a bit clearer exactly what's going on. You can repro this behavior with this as your Data Set query:
drop table if exists #foo
create table #foo(charge_type varchar(200) , global varchar(200))
select *
from #foo
WHERE GLOBAL IN (
CASE
WHEN #global IN ('None')
THEN charge_type
WHEN #global NOT IN ('None')
THEN #global
END
)
And configure #global as a parameter that allows multi-select. When the user selects multiple values SSRS transforms the query into:
drop table if exists #foo
create table #foo(charge_type varchar(200) , global varchar(200))
select *
from #foo
WHERE GLOBAL IN (
CASE
WHEN N'a',N'b' IN ('None')
THEN charge_type
WHEN N'a',N'b' NOT IN ('None')
THEN N'a',N'b'
END
)
Which fails with An expression of non-boolean type specified in a context where a condition is expected, near ','.

Related

Convert PostgreSQL to MS SQL

I am needing help converting a PostgreSQL query to MSSQ.
Below is what i have done so far but i am issuing with the function and array areas which i do not think are allowed in MS SQL.
Is there something that that i need to do change the function and looks the WHERE statement has an array in it too.
I have added the select statement for the #temp table but when i create the #temp table i am getting errors saying incorrect syntax
CREATE FUNCTION pm_aggregate_report
(
_facility_ids uuid[]
, _risk_ids uuid[] DEFAULT NULL::uuid[]
, _assignee_ids uuid[] DEFAULT NULL::uuid[]
, _start_date date DEFAULT NULL::date
, _end_date date DEFAULT NULL::date
)
RETURNS TABLE
(
facility character varying
, pm_id uuid, grouped_pm boolean
, risk_id uuid
, risk character varying
, pm_status_id uuid
, user_id uuid
, assignee text
, completed_by uuid
, total_labor bigint
)
CREATE TABLE #tmp_pm_aggregate
(
facility_id VARCHAR(126),
pm_id VARCHAR(126),
grouped_pm VARCHAR(126),
risk_id VARCHAR(126),
pm_status_id VARCHAR(126),
user_id VARCHAR(126),
completed_by VARCHAR(126)
)
SELECT DISTINCT
COALESCE(gp.facility_id, a.facility_id) as facility_id,
COALESCE(p.grouped_pm_id, p.id) as pm_id,
CASE WHEN p.grouped_pm_id IS NULL THEN false ELSE true END as grouped_pm,
COALESCE(gp.risk_id, a.risk_id) as risk_id,
COALESCE(gp.pm_status_id, p.pm_status_id) as pm_status_id,
COALESCE(gass.user_id, sass.user_id) as user_id,
COALESCE(gp.completed_by, p.completed_by) as completed_by
FROM pms p
JOIN assets a
ON p.asset_id = a.id
LEFT JOIN grouped_pms gp
ON p.grouped_pm_id = gp.id
LEFT JOIN assignees sass
ON p.id = sass.record_id
AND sass.type = 'single_pm'
LEFT JOIN assignees gass
ON p.grouped_pm_id = gass.record_id
AND gass.type = 'grouped_pm'
LEFT JOIN users u
ON (sass.user_id = u.id OR gass.user_id = u.id)
WHERE a.facility_id = ANY(_facility_ids)
AND NOT a.is_component
AND COALESCE(gp.pm_status_id, p.pm_status_id) in ('f9bdfc17-3bb5-4ec0-8477-24ef05ea3b9b', '06fc910c-3d07-4284-8f6e-8fb3873f5333')
AND COALESCE(gp.completion_date, p.completion_date) BETWEEN COALESCE(_start_date, '1/1/2000') AND COALESCE(_end_date, '1/1/3000')
AND COALESCE(gp.show_date, p.show_date) <= CURRENT_TIMESTAMP
AND COALESCE(gass.user_id, sass.user_id) IS NOT NULL
AND u.user_type_id != 'ec823d98-7023-4908-8006-2e33ddf2c11b'
AND (_risk_ids IS NULL OR COALESCE(gp.risk_id, a.risk_id) = ANY(_risk_ids)
AND (_assignee_ids IS NULL OR COALESCE(gass.user_id, sass.user_id) = ANY(_assignee_ids);
SELECT
f.name as facility,
t.pm_id,
t.grouped_pm,
t.risk_id,
r.name as risk,
t.pm_status_id,
t.user_id,
u.name_last + ', ' + u.name_first as assignee,
t.completed_by,
ISNULL(gwl.total_labor, swl.total_labor) as total_labor
FROM #tmp_pm_aggregate t
JOIN facilities f
ON t.facility_id = f.id
JOIN risks r
ON t.risk_id = r.id
JOIN users u
ON t.user_id = u.id
LEFT JOIN (SELECT wl.record_id, wl.user_id, SUM(wl.labor_time) as total_labor
FROM work_logs wl
WHERE wl.type = 'single_pm'
GROUP BY wl.record_id, wl.user_id) as swl
ON t.pm_id = swl.record_id
AND t.user_id = swl.user_id
AND t.grouped_pm = false
LEFT JOIN (SELECT wl.record_id, wl.user_id, SUM(wl.labor_time) as total_labor
FROM work_logs wl
WHERE wl.type = 'grouped_pm'
GROUP BY wl.record_id, wl.user_id) as gwl
ON t.pm_id = gwl.record_id
AND t.user_id = gwl.user_id
AND t.grouped_pm = true
ORDER BY facility,
assignee,
risk;
DROP TABLE #tmp_pm_aggregate;
You can create an inline Table Valued Function, and simply return a resultset from it. You do not need (and cannot use) a temp table, you do not declare the returned "rowset" shape.
For the array parameters, you can use a Table Type:
CREATE TYPE dbo.GuidList (value uniqueidentifier NOT NULL PRIMARY KEY);
Because the table parameters are actual tables, you must query them like this (NOT EXISTS (SELECT 1 FROM #risk_ids) OR ISNULL(gp.risk_id, a.risk_id) IN (SELECT r.value FROM #risk_ids))
The parameters must start with #
There is no boolean type, you must use bit
Always use deterministic date formats for literals. yyyymmdd works for dates. Do you need to take into account hours and minutes, because you haven't?
ISNULL generally performs better than COALESCE in SQL Server, as the compiler understands it better
You may want to pass a separate parameter showing whether you passed in anything for the optional table parameters
I suggest you look carefully at the actual query: why does it need DISTINCT? It performs poorly, and is usually a code-smell indicating poorly thought-out joins. Perhaps you need to combine the two joins on assignees, or perhaps you should use a row-numbering strategy somewhere.
CREATE FUNCTION dbo.pm_aggregate_report
(
#facility_ids dbo.GuidList
, #risk_ids dbo.GuidList
, #assignee_ids dbo.GuidList
, #start_date date
, #end_date date
)
RETURNS TABLE AS RETURN
SELECT DISTINCT -- why DISTINCT, perhaps rethink your joins
ISNULL(gp.facility_id, a.facility_id) as facility_id,
ISNULL(p.grouped_pm_id, p.id) as pm_id,
CASE WHEN p.grouped_pm_id IS NULL THEN CAST(0 AS bit) ELSE CAST(1 AS bit) END as grouped_pm,
ISNULL(gp.risk_id, a.risk_id) as risk_id,
ISNULL(gp.pm_status_id, p.pm_status_id) as pm_status_id,
ISNULL(gass.user_id, sass.user_id) as user_id,
ISNULL(gp.completed_by, p.completed_by) as completed_by
FROM pms p
JOIN assets a
ON p.asset_id = a.id
LEFT JOIN grouped_pms gp
ON p.grouped_pm_id = gp.id
LEFT JOIN assignees sass
ON p.id = sass.record_id
AND sass.type = 'single_pm'
LEFT JOIN assignees gass
ON p.grouped_pm_id = gass.record_id
AND gass.type = 'grouped_pm'
LEFT JOIN users u
ON (sass.user_id = u.id OR gass.user_id = u.id) -- is this doubling up your rows?
WHERE a.facility_id IN (SELECT f.value FROM #facility_ids f)
AND a.is_component = 0
AND ISNULL(gp.pm_status_id, p.pm_status_id) in ('f9bdfc17-3bb5-4ec0-8477-24ef05ea3b9b', '06fc910c-3d07-4284-8f6e-8fb3873f5333')
AND ISNULL(gp.completion_date, p.completion_date) BETWEEN ISNULL(#start_date, '20000101') AND ISNULL(#end_date, '30000101') -- perhaps use >= AND <
AND ISNULL(gp.show_date, p.show_date) <= CURRENT_TIMESTAMP
AND ISNULL(gass.user_id, sass.user_id) IS NOT NULL
AND u.user_type_id != 'ec823d98-7023-4908-8006-2e33ddf2c11b'
AND (NOT EXISTS (SELECT 1 FROM #risk_ids) OR ISNULL(gp.risk_id, a.risk_id) IN (SELECT r.value FROM #risk_ids))
AND (NOT EXISTS (SELECT 1 FROM #assignee_ids) OR ISNULL(gass.user_id, sass.user_id) IN (SELECT aid.value FROM #assignee_ids aid));

T-SQL - Update Table with data from the same table - Ambiguous table

I'm having trouble understanding why this query is not working. I get a message
The table '#PriceChanges' is ambiguous
The first mention of #PriceChanges is underlined
UPDATE #PriceChanges
SET MaxQty = MIN(ISNULL(PT.MinQty, 100000000))
FROM #PriceChanges P
LEFT JOIN #PriceChanges PT ON P.ChangeType = PT.ChangeType
AND P.ItemNo = PT.ItemNo
AND P.MinQty < PT.MinQty
So what I'm trying to achieve is setting the MAX quantity of a given line to the next MIN quantity found in the same table. If there's none found, then just make it a ridiculously high number (100,000,000)
The end result should look like something like this
MinQty MaxQty
-----------------
0 20
20 50
50 100
100 100000000
The ambiguity arises because the FROM clause of the UPDATE refers to the #PriceChanges table twice, so there is no way for SQL Server to know which of the two you intend to update. To resolve the ambiguity, instead of writing UPDATE #PriceChanges, use UPDATE P or UPDATE PT. Here's a trivial example:
create table #Test (id int, datum char(1));
insert #Test values (1, ' '), (2, ' ');
-- ERROR: The table '#Test' is ambiguous.
update #Test set datum = 'X' from #Test T1 inner join #Test T2 on T1.id = T2.id + 1;
-- CORRECT: Use the appropriate table alias to indicate which instance of #Test you want to update.
update T1 set datum = 'X' from #Test T1 inner join #Test T2 on T1.id = T2.id + 1;
Creating an intermediary table worked, I still wonder why this couldn't all be put into a single update
SELECT P.ChangeType, P.ItemNo, P.MinQty, MIN(PT.MinQty) AS MaxQty
INTO #MaxQty
FROM #PriceChanges P
LEFT JOIN #PriceChanges PT
ON P.ChangeType = PT.ChangeType
AND P.ItemNo = PT.ItemNo
AND P.MinQty < PT.MinQty
GROUP BY P.ChangeType, P.ItemNo, P.MinQty
UPDATE #PriceChanges
SET MaxQty = ISNULL(PM.MaxQty, 100000000)
FROM #PriceChanges P
LEFT JOIN #MaxQty PM
ON P.ChangeType = PM.ChangeType
AND P.ItemNo = PM.ItemNo
AND P.MinQty = PM.MinQty
I see no use for ISNULL(PT.MinQty, 100000000). MIN() ignores NULL values. And you don't need a self join. An updatable CTE or subquery works:
UPDATE pc
SET MaxQty = min_minqty
FROM (SELECT pc.*, MIN(pc.MinQty) OVER (PARTITION BY ItemNo, ChangeType) as min_minqty
FROM #PriceChanges pc
) pc
WHERE pc.MaxQty <> min_minqty;
EDIT:
You appear to want:
with pc as (
select pc.*,
lead(pc.MinQty) over (order by pc.MinQty) as next_MinQty
from #PriceChanges pc
)
update pc
set MaxQty = next_MinQty;

How to increase performance of this query?

I have an SQL query, it is running on MSSQL 2008 R2
View vMobileLastMobileHistory has about 1000 rows and
select * from vMobileLastMobileHistory is taking 0.2 sec
but this query is taking 5 seconds, how can I optimize this code?
(I think the problem is INTERSECT but I dont know how change this)
SELECT DISTINCT *
FROM
(
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN MobileType_DomainAction ON
MobileType_DomainAction.tiMobileType = vMobileLastMobileHistory.tiMobileType
LEFT OUTER JOIN MobileType_User ON
MobileType_User.MobileID = MobileType_DomainAction.ID
WHERE MobileType_User.UserID = #UserID OR #UserID = - 1
INTERSECT
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN dbo.Region_User ON
dbo.vMobileLastMobileHistory.strRegion = dbo.Region_User.strRegion
WHERE Region_User.iSystemUser = #UserID OR #UserID = - 1
INTERSECT
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN Contractor_User ON
vMobileLastMobileHistory.strContractor = Contractor_User.strContractor
WHERE Contractor_User.iSystemUser = #UserID OR #UserID = - 1
)
The problem is that if you have any indexes on your iSytemUser columns, the optimise is unable to use them because it has to account for a specific userID being passed, or returning all results, it would be better to logically separate your two cases. In addition, since you don't care about any columns in the auxiliary tables, you could use EXISTS in your case of specific users to take advantage of a semi join:
IF (#UserID = -1)
BEGIN
SELECT DISTINCT *
FROM vMobileLastMobileHistory;
END
ELSE
BEGIN
SELECT DISTINCT *
FROM vMobileLastMobileHistory AS mh
WHERE EXISTS
( SELECT 1
FROM Contractor_User AS cu
WHERE cu.strContractor = mh.strContractor
AND cu.iSystemUser = #UserID
)
AND EXISTS
( SELECT 1
FROM Region_User AS ru
WHERE ru.strRegion = mh.strRegion
AND ru.iSystemUser = #UserID
)
AND EXISTS
( SELECT 1
FROM MobileType_DomainAction AS da
INNER JOIN MobileType_User AS mu
ON mu.MobileID = da.ID
WHERE da.tiMobileType = mh.tiMobileType
AND mu.iSystemUser = #UserID
);
END
Now you can have two execution plans for each case (returning all results, or for a specific user), in each case you only need to read from vMobileLastMobileHistory once, and you also limit the sorts required by removing the INTERSECT and replacing with 3 EXISTS clauses.
If they don't already exist then you may also which to consider some indexes on your tables. A good way of finding out what indexes would help is to run the query in SQL Server Management Studio with the option "Show Actual Execution Plan" enabled, this will then show you any missing indexes.
Most of time Intersect and Inner Join will be same. You are not share your data, so based on my knowledge and this link, I just replace intersect query into Inner join query as :
--I think you don't need distinct upper query. If you have issue inform me.
SELECT DISTINCT vml.*
FROM vMobileLastMobileHistory vml
LEFT OUTER JOIN MobileType_DomainAction mtda ON mtda.tiMobileType = vml.tiMobileType
LEFT OUTER JOIN MobileType_User ON MobileType_User.MobileID = mtda.ID
LEFT OUTER JOIN dbo.Region_User ON dbo.vml.strRegion = dbo.Region_User.strRegion
LEFT OUTER JOIN Contractor_User ON vml.strContractor = Contractor_User.strContractor
WHERE
(MobileType_User.UserID = #UserID
and Region_User.iSystemUser = #UserID or Contractor_User.iSystemUser = #UserID
) OR #UserID = - 1

TSQL: Trying to turn joined select statement into update statement

Not the most complex problem but I've been looking at this one for a while and I'm at a block. Here is a TSQL select statement I want to turn into an update statement. The table structures are included for reference (server, db, and table names simplified from what they actually are).
SELECT m.ConfirmationCode as CodeInMain,
e.ConfirmationCode as CodeInEvents
FROM Server1.DB1.dbo.MainTable AS m
INNER JOIN Server2.DB1.dbo.Events AS e ON c.AccountCode = e.AccountCode
AND c.Commodity = (
SELECT Alias
FROM Server2.DB1.dbo.Commodities
WHERE pkCommodityId = e.fkCommodityId )
WHERE m.AccountCode = e.AccountCode
AND m.Brand IN( 'FTR', 'CER' );
Here are the referenced table schemas:
Server1.DB1.dbo.MainTable (ConfirmationCode varchar(100), AccountCode varchar(100), Commodity varchar(1), Brand varchar(3))
Server2.DB1.dbo.Events (ConfirmationCode varchar(100), AccountCode varchar(100), Commodity int)
Server2.DB1.dbo.Commodities (pkCommodityId int, Alias varchar(100))
Server 2 is linked to Server 1.
The current output of the select statement is:
CodeInMain | CodeInEvents
--------------------------
AN235cAc0a | NULL
CSORSX239c | NULL
...
All of my outputted information is as expected.
My goal is to update e.ConfirmationCode as CodeInEvents with the data in m.ConfirmationCode as CodeInMain but I am getting stuck on how to accommodate for the join. I realize that a cursor can be used to cycle through the contents of the above output when stored in a temporary table, but I would really like to be able to do this in a single update statement.
SQL Server has a non-ANSI extended UPDATE syntax that supports JOIN:
UPDATE e
SET e.ConfirmationCode = m.ConfirmationCode
FROM Server1.DB1.dbo.MainTable AS m
INNER JOIN Server2.DB1.dbo.Events AS e ON c.AccountCode = e.AccountCode
AND c.Commodity = (
SELECT Alias
FROM Server2.DB1.dbo.Commodities
WHERE pkCommodityId = e.fkCommodityId )
WHERE m.AccountCode = e.AccountCode
AND m.Brand IN( 'FTR', 'CER' );
got it.
Update e
set e.ConfirmationCode = m.ConfirmationCode
from Server2.DB1.dbo.Events e
inner join Server1.DB1.dbo.MainTable m on m.AccountCode = e.AccountCode and m.Commodity = (select Alias from Server2.DB1.dbo.Commodities where pkCommodityId = e.fkCommodityId)
where m.AccountCode = e.AccountCode and m.Brand in ('FTR', 'CER')

Conditional JOIN Statement SQL Server

Is it possible to do the following:
IF [a] = 1234 THEN JOIN ON TableA
ELSE JOIN ON TableB
If so, what is the correct syntax?
I think what you are asking for will work by joining the Initial table to both Option_A and Option_B using LEFT JOIN, which will produce something like this:
Initial LEFT JOIN Option_A LEFT JOIN NULL
OR
Initial LEFT JOIN NULL LEFT JOIN Option_B
Example code:
SELECT i.*, COALESCE(a.id, b.id) as Option_Id, COALESCE(a.name, b.name) as Option_Name
FROM Initial_Table i
LEFT JOIN Option_A_Table a ON a.initial_id = i.id AND i.special_value = 1234
LEFT JOIN Option_B_Table b ON b.initial_id = i.id AND i.special_value <> 1234
Once you have done this, you 'ignore' the set of NULLS. The additional trick here is in the SELECT line, where you need to decide what to do with the NULL fields. If the Option_A and Option_B tables are similar, then you can use the COALESCE function to return the first NON NULL value (as per the example).
The other option is that you will simply have to list the Option_A fields and the Option_B fields, and let whatever is using the ResultSet to handle determining which fields to use.
This is just to add the point that query can be constructed dynamically based on conditions.
An example is given below.
DECLARE #a INT = 1235
DECLARE #sql VARCHAR(MAX) = 'SELECT * FROM [sourceTable] S JOIN ' + IIF(#a = 1234,'[TableA] A ON A.col = S.col','[TableB] B ON B.col = S.col')
EXEC(#sql)
--Query will be
/*
SELECT * FROM [sourceTable] S JOIN [TableB] B ON B.col = S.col
*/
You can solve this with union
select a, b
from tablea
join tableb on tablea.a = tableb.a
where b = 1234
union
select a, b
from tablea
join tablec on tablec.a = tableb.a
where b <> 1234
I disagree with the solution suggesting 2 left joins. I think a table-valued function is more appropriate so you don't have all the coalescing and additional joins for each condition you would have.
CREATE FUNCTION f_GetData (
#Logic VARCHAR(50)
) RETURNS #Results TABLE (
Content VARCHAR(100)
) AS
BEGIN
IF #Logic = '1234'
INSERT #Results
SELECT Content
FROM Table_1
ELSE
INSERT #Results
SELECT Content
FROM Table_2
RETURN
END
GO
SELECT *
FROM InputTable
CROSS APPLY f_GetData(InputTable.Logic) T
I think it will be better to think about your query in a different way and treat them more like sets.
I do believe if you make two separate queries then join them using UNION, It will be much better in performance and more readable.

Resources