Inner join on a partial column in Access - ms-access

I'm attempting to join two tables in MS Access 2010 where the join condition is part of(A.col1) = B.col2. I've not been able to figure out how to do this so far.
My two tables have these critical columns:
Table 1 has column ICD9 Code-Description* with values like:842.00 - Sprain/strain, wrist924.11 - Contusion, knee
Table 2 has column Dx with values like:842924.11
I have tried these two join criteria:
FROM Table1
INNER JOIN Table2 ON Table1.Replace(LTrim(Replace(Left(ICD9Code-Description],
(InStr(1,[ICD9Code-Description]," "))-1),"0"," "))," ","0")
= Table2.Dx
and
SELECT ICD9
FROM Table2 INNER JOIN
(SELECT Replace(LTrim(Replace(Left([ICD9 Code-Description],
(InStr(1,[ICD9 Code-Description]," "))-1),"0"," "))," ","0") AS ICD9
FROM Table1)
ON Diag.DX = ICD9
Neither of which Access likes.
I'd like to avoid pulling out the join criteria portion into its own column in Table1 if at all possible.
What would be the Access way of doing this?
*Don't hate me for the column name. I didn't create it, I just have to support it.

The Val() function "Returns the numbers contained in a string as a numeric value of appropriate type." (See the Val Function help topic in Access' built-in help system.)
The "neat thing" for your situation is it reads characters from the string until it encounters a character which can't be part of a valid number. But then it doesn't throw an error. It just keeps the numeric characters it's already collected and ignores the rest.
Here's two of your examples in the Immediate window ...
? Val("842.00 - Sprain/strain, wrist")
842
? Val("924.11 - Contusion, knee")
924.11
So Val() should make your JOIN much simpler, even though you would need to also apply it on the Table2.Dx strings ...
FROM
Table1 INNER JOIN Table2
ON Val(Table1.[ICD9Code-Description]) = Val(Table2.Dx)

Related

SELECT statement inside a CASE statement in SNOWFLAKE

I have a query where i have "TEST"."TABLE" LEFT JOINED to PUBLIC."SchemaKey". Now in my final select statement i have a case statement where i check if c."Type" = 'FOREIGN' then i want to grab a value from another table but the table name value i am using in that select statement is coming from the left joined table column value. I've tried multiple ways to get to work but i keep getting an error, although if i hard code the table name it seems to work. i need the table name to come from c."FullParentTableName". Is what i am trying to achieve possible in snowflake and is there a way to make this work ? any help would be appreciated !
SELECT
c."ParentColumn",
c."FullParentTableName",
a."new_value",
a."column_name"
CASE WHEN c."Type" = 'FOREIGN' THEN (SELECT "Name" FROM TABLE(c."FullParentTableName") WHERE "Id" = 'SOME_ID') ELSE null END "TestColumn" -- Need assistance on this line...
FROM "TEST"."TABLE" a
LEFT JOIN (
select s."Type", s."ParentSchema", s."ParentTable", s."ParentColumn", concat(s."ParentSchema",'.','"',s."ParentTable",'"') "FullParentTableName",s."ChildSchema", s."ChildTable", trim(s."ChildColumn",'"') "ChildColumn"
from PUBLIC."SchemaKey" as s
where s."Type" = 'FOREIGN'
and s."ChildTable" = 'SOMETABLENAME'
and "ChildSchema" = 'SOMESCHEMANAME'
) c
on a."column_name" = c."ChildColumn"
Thanks !
In Snowflake you cannot dynamically use the partial results as tables.
You can use a single bound value via identifier to bind a value to table name
But you could write a Snowflake Scripting but it would need to explicitly join the N tables. Thus if you N is fixed, you should just join those.

Joining and filtering one-to-many relationship

I need some help about optimal structuring of SQL query. I have model like this:
I'm trying some kind of join between tables NON_NATURAL_PERSON and NNP_NAME. Because I have many names in table NNP_NAME for one person I can't do one-to-one SELECT * from NON_NATURAL_PERSON inner join NNP_NAME etc. That way I'll get extra rows for every name one person has.
Data in tables:
How to extend this query to get rows marked red on picture shown below? My wannabe query criteria is: Always join name of typeA only if exists. If not, join name of typeB. If neither exists join name of typeC.
SELECT nnp.ID, name.NAME, name.TYPE
FROM NON_NATURAL_PERSON nnp
INNER JOIN NNP_NAME name ON (name.NON_NATURAL_PERSON = nnp.ID)
If type is spelled exactly as it's written (typeA, typeB, typeC) then you can use MIN() function:
SELECT NON_NATURAL_PERSON, MIN(type) AS min_type
FROM NNP_NAME
GROUP BY NON_NATURAL_PERSON
if you also want the username you can use this query:
SELECT
n1.NON_NATURAL_PERSON AS ID,
n1.Name,
n1.Type
FROM
NNP_NAME n1 LEFT JOIN NNP_NAME n2
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type
WHERE
n2.type IS NULL
Please see this fiddle. If Types are not literally sorted, change this line:
AND n1.Type > n2.type
with this:
AND FIELD(n1.Type, 'TypeA', 'TypeB', 'TypeC') >
FIELD(n2.type, 'TypeA', 'TypeB', 'TypeC')
MySQL FIELD(str, str1, str2, ...) function returns the index (position) of str in the str1, str2, ... list, and 0 if str is not found. You want to get the "first" record, ordered by type, for every NON_NATURAL_PERSON. There are multiple ways to get this info, I chose a self join:
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type -- or filed function
with the WHERE condition:
WHERE n2.type IS NULL
this will return all rows where the join didn't succeed - the join won't succeed when there is not n2.type that is less than n1.type - it will return the first record.
Edit
If you want a platform independent solution, avoiding the creation of new tables, you could use CASE WHEN, just change
AND n1.Type > n2.Type
with
AND
CASE
WHEN n1.Type='TypeA' THEN 1
WHEN n1.Type='TypeB' THEN 2
WHEN n1.Type='TypeC' THEN 3
END
>
CASE
WHEN n2.Type='TypeA' THEN 1
WHEN n2.Type='TypeB' THEN 2
WHEN n2.Type='TypeC' THEN 3
END
There is a piece of information missing. You say:
Always join name of typeA only if exists. If not, join name of typeB. If neither exists join name of typeC.
But you do not indicate why you prefer typeA over typeB. This information is not included in your data.
In the answer of #fthiella, either lexicographical is assumed, or an arbitrary order is given using FIELD. This is also the reason why two joins with the table nnp_name is necessary.
You can solve this problem by adding a table name_type (id, name, order) and changing the type column to contain the id. This will allow you to add the missing information in a clean way.
With an additional join with this new table, you will be able get the preferred nnp_name for each row.

Multiple joins involving same table produces "column doesn't exist" error - MySQL

I'm new to joins and I'm sure this is ridiculously simple. If I remove one join in the query the remainder of the query works regardless of which join I remove. But as shown it gives the error saying the column doesn't exist. Any pointers?
select
loc_carr.address1 as carr_addr1,
loc_cust.address1 as cust_addr1
from db_name.carrier, db_name.customer
join db_name.location as loc_carr on vats.carrier.location_id=loc_carr.location_id
join db_name.location as loc_cust on vats.customer.location_id=loc_cust.location_id
thanks
I'll take a guess that there is a column named something like carrier_id that can be used to join the carrier and customer tables. Given that assumption, try this:
select
loc_carr.address1 as carr_addr1
, loc_cust.address1 as cust_addr1
from vats.carrier as a
join vats.customer as b
on b.carrier_id=a.carrier_id
join vats.location as loc_carr
on loc_carr.location_id=a.location_id
join vats.location as loc_cust
on loc_cust.location_id=b.location_id
Notice the use of aliases for the table references to make things easier to read. Also note how I'm using explicit SQL join syntax (instead of listing tables separated by commas).
#Bob Duell has the solution for your problem. To understand better why this error is produced, notice that in the FROM clause, you "join" tables using both explicit JOIN syntax and the implicit joins with comma: , which is (almost) equivalent to a CROSS JOIN. The precedence however of JOIN is stronger than the comma , operator. So, that part is parsed like this:
FROM
( db_name.carrier )
,
( ( db_name.customer
JOIN db_name.location AS loc_carr
ON carrier.location_id = loc_carr.location_id -- this line
) -- gives the error
JOIN join db_name.location AS loc_cust
ON customer.location_id = loc_cust.location_id
)
In the mentioned line above, the vats.carrier.location_id throws the error, as there is no carrier table in that scope (inside that parenthesis).

Alias a column name on a left join

Let's say I have two tables, and both their primary identifiers use the name 'id'. If I want to perform a join with these two tables, how would I alias the id of the table that I want to join with the former table?
For example:
SELECT * FROM `sites_indexed` LEFT JOIN `individual_data` ON `sites_indexed`.`id` = `individual_data`.`site_id` WHERE `url` LIKE :url
Now, site_id is supposed to link up with sites_indexed.id. The actual id which represents the row for individual_data however has the same title as sites_indexed.
Personally, I like to just use the name id for everything, as it keeps things consistent. When scripting server-side however, it can make things confusing.
e.g.
$var = $result['id'];
Given the aforementioned query, wouldn't this confuse the interpreter?
Anyway, how is this accomplished?
Instead of selecting all fields with "SELECT *" you should explicitly name each field you need, aliasing them with AS as required. For example:
SELECT si.field1 as si_field1,
si.field2 as si_field2,
ind_data.field1 as ind_data_field1
FROM sites_indexed as si
LEFT JOIN individual_data as ind_data
ON si.id = ind_data.site_id
WHERE `url` LIKE :url
And then you can reference the aliased names in your result set.
This thread is old and i found because i had the same problem. Now i have a better solution.
The answer given by Paul McNett and antun forces you to list all fields but in some cases this is impossible (too much fields to list), so you can keep the * and alias only the fields you want (typically the fields that have the same name and will override each other).
Here's how :
SELECT *, t.myfield as myNewName
FROM table t ... continue your query
you can add as much aliases as you want by adding comas.
Using this expression you will get results with columns id (from table sites_indexed) and id2 (alias for column id from table individual_data)
SELECT t1 . *, t2 . * FROM sites_indexed t1
LEFT JOIN (select id as id2, other_field1, other_field2 FROM individual_data) t2 ON t1.id = t2.site_id WHERE your_statement
The problem is that you're using the * wildcard. If you explicitly list the column names in your query, you can give them aliases:
SELECT `sites_indexed`.`id` AS `sites_indexed_id`,
`individual_data`.`id` AS `individual_data_id`
FROM `sites_indexed`
LEFT JOIN `individual_data` ON `sites_indexed`.`id` = `individual_data`.`site_id`
WHERE `url` LIKE :url
Then you can reference them via the alias:
$var = $result['sites_indexed_id'];
$var_b = $result['individual_data_id'];

MySQL Inner Join should not produce results ... but it does

I've come across a situation where an incorrect query was generated:
select a.id, e.ethnicity_cd, e.appl_person_id from applicants a
inner join ucpsom_production_ucpsom_production.ETHNICITY e
on e.appl_person_id = a.id
where a.amc_id = 12977319
The error is in the join statement. The statement should read "e.appl_person_id = a.appl_person_id" and return no records because there is no e.appl_person_id value equal to "80cbacb2-8444-11df-acd2-12313b079cc4", the a.id value.
What is happening then is that MySQL is matching values of 80 (for e.appl_person_id) to values of "80cbacb2-8444-11df-acd2-12313b079cc4" (for a.id). Thus:
80 = "80cbacb2-8444-11df-acd2-12313b079cc4".
*Note: e.app_person_id is a decimal and a.id is a string.* It looks like MySQl is comparing the first two characters of the a.id value to the e.appl_person_id value.
Can anyone explain why this is happening with MySQL, and also, is this MySQL specific in nature?
Thanks much.
Looks like MySQL is attempting to do an implicit conversion of data types (from string to int in this case).
Most databases will do some conversions implicitly, for example SQL server will implicitly convert from smallint to int, but which conversions are done implicitly would be DBMS specific.