Coalesce not working in an update join - sql

I have an update query where I am trying to find the net interest from multiple accounts on three different transaction tables deposits, checks, and general entries. The problem I'm running into is when one of those tables has no entries for a loan number to an interest account the select returns nothing and subsequently displays a null in the production table too. Negating the other tables if they return rows from interest account. If all three tables have a row for interest the query works fine.
Here's the code:
UPDATE Prod
SET Prod.InterestSpread = (T1.Amount+T2.Amount-T3.Amount)
FROM dbo.Production_Pipeline as Prod
LEFT JOIN
(
SELECT LoanNumber,COALESCE(SUM(JournalLineAmount),0)as Amount
FROM dbo.GeneralLedger
WHERE (JournalLineAccountRefListID = 'BB0000-1103842703'
OR JournalLineAccountRefListID = '800001DA-1202763722')
) AS T1
ON T1.LoanNumber = Prod.LoanNumber
LEFT JOIN
(
SELECT LoanNumber,COALESCE(SUM(DepositLineAmount),0)as Amount
FROM dbo.DepositLedger
WHERE ( DepositLineAccountRefListID = 'BB0000-1103842703'
OR DepositLineAccountRefListID = '800001DA-1202763722')
) AS T2
ON T2.LoanNumber = Prod.LoanNumber
LEFT JOIN
(
SELECT LoanNumber,COALESCE(SUM(ExpenseLineAmount),0) AS Amount
FROM dbo.CheckLedger
WHERE(ExpenseLineAccountRefListID = '800002B4-1308771936'
OR ExpenseLineAccountRefListID = 'D30000-1105022008'
OR ExpenseLineAccountRefListID = '8000029E-1283179936'
OR ExpenseLineAccountRefListID = 'BB0000-1103842703'
OR ExpenseLineAccountRefListID = '800001DA-1202763722')
) AS T3
ON T3.LoanNumber = Prod.LoanNumber
So an inccorect result update looks like
T1Amount: 496.08
T2Amount:
T3Amount: 373.92
Interest Spread: NULL
I've done some quite a bit of research on this site but, have been unable to apply your wisdom to my specific issue so any help here would greatly be appreciated.

Move your COALESCE statement to outside of the JOIN and remove it from the subqueries:
UPDATE Prod
SET Prod.InterestSpread =
COALESCE(T1.Amount,0)+COALESCE(T2.Amount,0)-COALESCE(T3.Amount,0)
...
The problem is your subqueries return no results, thus coalesce inside of that cannot be applied to the field. By using it outside of the outer join, you ensure if the result is null, it converts properly.

Related

Non null value associated with least value in other column

My data is like this:
Desired output:
I have tried using following SQL:
CASE
WHEN (MINDAY_DIFF > 0) AND (MINDAY_DIFF IS NOT NULL)
THEN FIRST_VALUE(BP_MED) OVER (PARTITION BY ID ORDER BY MINDAY_DIFF ASC)
END AS DRUG
This returns NULL.
I also tried
CASE
WHEN (MINDAY_DIFF > 0)
THEN BP_MED
ELSE NULL
END AS DRUG
It returns both non-null values of BP_MED.
I also tried NVL but that didn't work either.
Since it is in Netezza. There are fewer solutions online. Please help.
The concept here is the following working inside out:
We didn't always have analytics to make things easier: So not knowing Netezza I took a more... antiquated approach. There may be better/more efficient ways; which I would look for given a place to play around with; but I think this would work in most any RDBMS as I tried to avoid any RDBMS Specific aspects unless we're dealing with pre left join supported RDBMS.
Find the Min ID and the day difference for that ID in a result set (MinAndID)
LEFT Join back to the baseSet to get all possible values specifically to get BP_Med
Then Join back to base Table to ensure we get ALL records and then populate only the BP_Med which links to the minDay_Diff. Since it's a left join only 1 record per ID should return.
UNTESTED:
SELECT A.*, DesiredDrug.BP_MED
FROM TABLE A
LEFT JOIN (SELECT ID, Fill_Date, BP_MED, MinDay_Diff
FROM TABLE BaseSet
INNER JOIN (SELECT MIN(MINDAY_DIFF) MDD, ID
FROM TABLE
WHERE ID is not null
GROUP BY ID) MinAndID
on BaseSet.ID = MinAndID.ID
and BaseSet.MinDay_Diff = MinAndID.MDD) DesiredDrug
on A.ID = DesiredDrug
and A.Fill_Date = DesiredDrug.Fill_Date
and A.BP_Med= DesiredDrug.BP_Med
and A.MinDay_Diff = DesiredDrug.MinDay_Diff

Number of Records don't match when Joining three tables

Despite going through every material I could possibly find on the internet, I haven't been able to solve this issue myself. I am new to MS Access and would really appreciate any pointers.
Here's my problem - I have three tables
Source1084 with columns - Department, Sub-Dept, Entity, Account, +few more
R12CAOmappingTable with columns - Account, R12_Account
Table4 with columns - R12_Account, Department, Sub-Dept, Entity, New Dept, LOB +few more
I have a total of 1084 records in Source and the result table must also contain 1084 records. I need to draw a table with all the columns from Source + R12_account from R12CAOmappingTable + all columns from Table4.
Here is the query I wrote. This yields the right columns but gives me more or less number of records with interchanging different join options.
SELECT rmt.r12_account,
srb.version,
srb.fy,
srb.joblevel,
srb.scenario,
srb.department,
srb.[sub-department],
srb.[job function],
srb.entity,
srb.employee,
table4.lob,
table4.product,
table4.newacct,
table4.newdept,
srb.[beg balance],
srb.jan,
srb.feb,
srb.mar,
srb.apr,
srb.may,
srb.jun,
srb.jul,
srb.aug,
srb.sep,
srb.oct,
srb.nov,
srb.dec,
rmt.r12_account
FROM (source1084 AS srb
LEFT JOIN r12caomappingtable AS rmt
ON srb.account = rmt.account)
LEFT JOIN table4
ON ( srb.department = table4.dept )
AND ( srb.[sub-department] = table4.subdept )
AND ( srb.entity = table4.entity )
WHERE ( ( ( srb.[sub-department] ) = table4.subdept )
AND ( ( srb.entity ) = table4.entity )
AND ( ( rmt.r12_account ) = table4.r12_account ) );
In this simple example, Table1 contains 3 rows with unique fld1 values. Table2 contains one row, and the fld1 value in that row matches one of those in Table1. Therefore this query returns 3 rows.
SELECT *
FROM
Table1 AS t1
LEFT JOIN Table2 AS t2
ON t1.fld1 = t2.fld1;
However if I add the WHERE clause as below, that version of the query returns only one row --- the row where the fld1 values match.
SELECT *
FROM
Table1 AS t1
LEFT JOIN Table2 AS t2
ON t1.fld1 = t2.fld1
WHERE t1.fld1 = t2.fld1;
In other words, that WHERE clause counteracts the LEFT JOIN because it excludes rows where t2.fld1 is Null. If that makes sense, notice that second query is functionally equivalent to this ...
SELECT *
FROM
Table1 AS t1
INNER JOIN Table2 AS t2
ON t1.fld1 = t2.fld1;
Your situation is similar. I suggest you first eliminate the WHERE clause and confirm this query returns at least your expected 1084 rows.
SELECT Count(*) AS CountOfRows
FROM (source1084 AS srb
LEFT JOIN r12caomappingtable AS rmt
ON srb.account = rmt.account)
LEFT JOIN table4
ON ( srb.department = table4.dept )
AND ( srb.[sub-department] = table4.subdept )
AND ( srb.entity = table4.entity );
After you get the query returning the correct number of rows, you can alter the SELECT list to return the columns you want. But the columns aren't really the issue until you can get the correct rows.
Without knowing your tables values it is hard to give a complete answer to your question. The issue that is causing you a problem based on how you described it. Is more then likely based on the type of joins you are using.
The best way I found to understand what type of joins you should be using would referencing a Venn diagram explaining the different type of joins that you can use.
Jeff Atwood also has a really good explanation of SQL joins on his site using the above method as well.
Best to just use the query builder. Drop in your main table. Choose the columns you want. Now for any of the other lookup values then simply drop in the other tables, draw the join line(s), double click and use a left join. You can do this for 2 or 30 columns that need to "grab" or lookup other values from other tables. The number of ORIGINAL rows in the base table returned should ALWAYS remain the same.
So just use the query builder and follow the above.
The problem with your posted SQL is you NESTED the joins inside (). Don't do that. (or let the query builder do this for you – they tend to be quite messy but will also work).
Just use this:
FROM source1084 AS srb
LEFT JOIN r12caomappingtable AS rmt
ON srb.account = rmt.account
LEFT JOIN table4
ON ( srb.department = table4.dept )
AND ( srb.[sub-department] = table4.subdept )
AND ( srb.entity = table4.entity )
As noted, I don't see why you are "repeating" the conditions again in the where clause.

Join with select SQL query?

I'm trying to run a query on a table (the one Wordpress uses) where I want to select the ID and post_type columns from one table, then do a Left Join to another table, two separate times (getting separate data).
This is what I have so far, but it's not cutting the mustard:
SELECT derby_posts.id AS pID,
derby_posts.post_type AS tier
FROM derby_posts
LEFT JOIN (SELECT derby_postmeta.post_id AS dbID1,
derby_postmeta.meta_key AS dbMeta1)
ON pid = dbid1
AND dbmeta1 = 'twitter'
LEFT JOIN (SELECT derby_postmeta.post_id AS dbID2,
derby_postmeta.meta_key AS dbMeta2)
ON pid = dbid2
AND dbmeta2 = 'website'
WHERE tier IN ('local', 'regional', 'national')
I'm sure I'm missing something super simple...
Edit: here's the solution that worked for me. Table alias helped, putting all my SELECT statements together cleaned things up. Also, I realized I could remove items from the SELECT, even though I'm using them in the Join, which cleans up the results a lot.
SELECT
db.ID as id,
db.post_type as tier,
dpm1.meta_value as twitter,
dpm2.meta_value as website
FROM derby_posts db
LEFT JOIN derby_postmeta dpm1 ON (db.ID = dpm1.post_id AND dpm1.meta_key = 'twitter' )
LEFT JOIN derby_postmeta dpm2 ON (db.ID = dpm2.post_id AND dpm2.meta_key = 'website' )
WHERE db.post_type IN ('local','regional','national')
I 'm sure I'm missing something super simple...
You are right!
You need to give your selects an alias, and use that alias in the ON clause. You are also missing a FROM <table> - a required part of a SELECT statement that reads from a table:
LEFT JOIN (
SELECT derby_postmeta.post_id AS dbID1,
derby_postmeta.meta_key AS dbMeta1
FROM someTable
) dpm ON pid = dpm.dbid1 AND dpm.dbmeta1 = 'twitter'
I gave the results of your SELECT an alias dpm, and used it to "link up" the rows from the inner select to the rows of your outer select.
SELECT
db.derby_posts.ID as pID,
db.derby_posts.post_type as tier,
dpm1.post_id as dbID1,
dpm1.meta_key as dbMeta1,
dpm2.post_id as dbID2,
dpm2.meta_key as dbMeta2
FROM derby_posts db
LEFT JOIN derby_postmeta dpm1 ON (db.pID = dpm1.post_id AND dpm1.meta_key= 'twitter')
LEFT JOIN derby_postmeta dpm2 ON (db.pID = dbm2.post_id AND dbm2.meta_key = 'website')
WHERE tier IN ('local','regional','national')

Azure stored procedure out value

I've been trying to assemble a stored procedure on my Azure database that when it runs the query, it returns one output value from one specific column.
The likelihood of multiple results is zero since the the table being queried has 3 columns, and the query must mach 2. Then it grabs data from another table. The key is I need the first query to output the value in order to commence the second query.
At present I have 2 procedures, I would like to have one.
Query is as such for the moment:
select
customers_catalogs_define.catalog_id
from
customers_catalogs
left outer join
customers_catalogs_define on customers_catalogs.catalog_id = customers_catalogs_define.catalog_id
where
customers_catalogs.catalog_unique_identifier = #catalog_unique
AND customers_catalogs_define.customer_id = #customer_id
The output of course is the catalog_id. From that I take it into another query which I have that does the actual list retrieval. At the very least I would like to add a line that simply states #catalog_id = output
Thanks
You have two options basically to have this work :
Since I haven't seen your second query, just make sure its querying the correct table listed below as CUSTOMERS_CATALOGS_DEFINE
Using a variable as you suggested:
DECLARE #CATALOG_ID INT
SET #CATALOG_ID = (
SELECT CUSTOMERS_CATALOGS_DEFINE.CATALOG_ID
FROM CUSTOMERS_CATALOGS
LEFT OUTER JOIN CUSTOMERS_CATALOGS_DEFINE
ON CUSTOMERS_CATALOGS.CATALOG_ID = CUSTOMERS_CATALOGS_DEFINE.CATALOG_ID
WHERE CUSTOMERS_CATALOGS.CATALOG_UNIQUE_IDENTIFIER = #CATALOG_UNIQUE
AND CUSTOMERS_CATALOGS_DEFINE.CUSTOMER_ID = #CUSTOMER_ID )
SELECT *
FROM CUSTOMERS_CATALOGS_DEFINE
WHERE CATALOG_ID = #CATALOG_ID
Second option would be to do it in one query:
SELECT *
FROM CUSTOMERS_CATALOGS_DEFINE
WHERE CATALOG_ID IN (
SELECT CUSTOMERS_CATALOGS_DEFINE.CATALOG_ID
FROM CUSTOMERS_CATALOGS
LEFT OUTER JOIN CUSTOMERS_CATALOGS_DEFINE
ON CUSTOMERS_CATALOGS.CATALOG_ID = CUSTOMERS_CATALOGS_DEFINE.CATALOG_ID
WHERE CUSTOMERS_CATALOGS.CATALOG_UNIQUE_IDENTIFIER = #CATALOG_UNIQUE
AND CUSTOMERS_CATALOGS_DEFINE.CUSTOMER_ID = #CUSTOMER_ID
)

Left Join With Where Clause

I need to retrieve all default settings from the settings table but also grab the character setting if exists for x character.
But this query is only retrieving those settings where character is = 1, not the default settings if the user havent setted anyone.
SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT JOIN `character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1'
So i should need something like this:
array(
'0' => array('somekey' => 'keyname', 'value' => 'thevalue'),
'1' => array('somekey2' => 'keyname2'),
'2' => array('somekey3' => 'keyname3')
)
Where key 1 and 2 are the default values when key 0 contains the default value with the character value.
The where clause is filtering away rows where the left join doesn't succeed. Move it to the join:
SELECT `settings`.*, `character_settings`.`value`
FROM `settings`
LEFT JOIN
`character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
AND `character_settings`.`character_id` = '1'
When making OUTER JOINs (ANSI-89 or ANSI-92), filtration location matters because criteria specified in the ON clause is applied before the JOIN is made. Criteria against an OUTER JOINed table provided in the WHERE clause is applied after the JOIN is made. This can produce very different result sets. In comparison, it doesn't matter for INNER JOINs if the criteria is provided in the ON or WHERE clauses -- the result will be the same.
SELECT s.*,
cs.`value`
FROM SETTINGS s
LEFT JOIN CHARACTER_SETTINGS cs ON cs.setting_id = s.id
AND cs.character_id = 1
If I understand your question correctly you want records from the settings database if they don't have a join accross to the character_settings table or if that joined record has character_id = 1.
You should therefore do
SELECT `settings`.*, `character_settings`.`value`
FROM (`settings`)
LEFT OUTER JOIN `character_settings`
ON `character_settings`.`setting_id` = `settings`.`id`
WHERE `character_settings`.`character_id` = '1' OR
`character_settings`.character_id is NULL
You might find it easier to understand by using a simple subquery
SELECT `settings`.*, (
SELECT `value` FROM `character_settings`
WHERE `character_settings`.`setting_id` = `settings`.`id`
AND `character_settings`.`character_id` = '1') AS cv_value
FROM `settings`
The subquery is allowed to return null, so you don't have to worry about JOIN/WHERE in the main query.
Sometimes, this works faster in MySQL, but compare it against the LEFT JOIN form to see what works best for you.
SELECT s.*, c.value
FROM settings s
LEFT JOIN character_settings c ON c.setting_id = s.id AND c.character_id = '1'
For this problem, as for many others involving non-trivial left joins such as left-joining on inner-joined tables, I find it convenient and somewhat more readable to split the query with a with clause. In your example,
with settings_for_char as (
select setting_id, value from character_settings where character_id = 1
)
select
settings.*,
settings_for_char.value
from
settings
left join settings_for_char on settings_for_char.setting_id = settings.id;
The way I finally understand the top answer is realising (following the Order Of Execution of the SQL query ) that the WHERE clause is applied to the joined table thereby filtering out rows that do not satisfy the WHERE condition from the joined (or output) table. However, moving the WHERE condition to the ON clause applies it to the individual tables prior to joining. This enables the left join to retain rows from the left table even though some column entries of those rows (entries from the right tables) do not satisfy the WHERE condition.
The result is correct based on the SQL statement. Left join returns all values from the right table, and only matching values from the left table.
ID and NAME columns are from the right side table, so are returned.
Score is from the left table, and 30 is returned, as this value relates to Name "Flow". The other Names are NULL as they do not relate to Name "Flow".
The below would return the result you were expecting:
SELECT a.*, b.Score
FROM #Table1 a
LEFT JOIN #Table2 b
ON a.ID = b.T1_ID
WHERE 1=1
AND a.Name = 'Flow'
The SQL applies a filter on the right hand table.