Use switch and "in" in MS-Access Select Query - sql

let's say I have two tables, where the first one contains my data:
Automatic
Manual
X1
X1
Y
Y27
and a lookup table
Lookup
X1
Y27
...
I want to select the value from the first table, IF it is contained in the lookup table.
So for the second row, it should take the value Y27, because Y ist not in the lookup table.
I tried it with this query:
Select
Switch(
Automatic in (SELECT Lookup FROM LookupTable), Automatic,
True, Manual,
) AS ValidEntry
FROM Datatable;
My query as text: Check if the value from "Automatic" is inside the lookup table, if yes -> take the value, if not, take the value from the other column "manual" and return an entry named "ValidEntry".

Use a INNER JOIN, it should be much faster.
select somedata from table1 t
inner join lookupTbl l on l.lookupfield = t.automatic
With IN clause:
select somedata from table1 t
WHERE t.automatic IN (select lookupfield FROM lookupTbl)

This is what you need to do:
SELECT NZ( LookupTableAutomatic.Lookup, LookupTableManual.Lookup) AS Lookup
FROM (LookupTable AS LookupTableManual INNER JOIN DataTable
ON LookupTableManual.Lookup = DataTable.Manual)
LEFT OUTER JOIN LookupTable AS LookupTableAutomatic ON LookupTableAutomatic.Lookup = DataTable.Automatic;
By way of explanation the NZ Function returns the first parameter if it is not null, otherwise it takes the second. The lookup table is joined twice: the Manual Lookup is an INNER JOIN, as I am assuming that there will always be a fallback value, whereas the Automatic lookup is joined as an OUTER JOIN, meaning that it returns NULL when the value is not matched.

Related

Postgresql LEFT JOIN returns more results than expected

I have a table called product_simulations which has columns
product_id and data
data here represents JSON B that has {'simulation_id':1'}
Then, I have simulation table that has columns
simulation_id and simulation_name
I simply want to grab simulation_id from product simulation, then perform left join so that I can also have simulation_name, my product_sim has about 2k records, where as my simulation_table has over 1m record, when I do left join, it returns over 200k record, instead of 2k. Is left join not what I am looking for here? I simply want to write a query where along all the columns from product_simulations, for those simulation_id, I also want to get simulation_name.
SELECT ps.*,
s.simulation_name*,
ps.data ->> 'simulation_id' as simulation_id
FROM pricing.product_simulations ps
LEFT JOIN simulation s on s.simulation_id = simulation_id
You cannot use a column alias in the WHERE clause, because WHERE is executed before the output columns are calculated.
Consequently, both simulation_ids in your join condition
ON s.simulation_id = simulation_id
refer to the column in simulation. The condition thus is the same as
ON s.simulation_id IS NOT NULL
which produces way more result rows than you want.
Use the expression instead of the alias in the join condition:
ON s.simulation_id = (ps.data ->> 'simulation_id')::bigint
(assuming that simulation_id is a bigint)
Let me remark that using JSON in this table design was a bad idea.

Convert columnB value if columnA = X in SQL

Overview
I have an inner join statement that links 5 tables together which is working fantastically if i do say so myself.
Now one of the values returned is in Hex and it is in a column named Value however, the Value column also contains other values and so i cannot simply convert the whole column.
Every Hex entry into column Value has an identifier of 18 in a column called DataTypeID.
The Question
How can i convert just the Hex entry in column Value if DataTypeID=18.
I know this needs a function with:
SELECT CONVERT(INT, CONVERT(VARBINARY
But I am unsure of how to write it and where to place it, is it before my inner join statement or after?
SELECT Data.Value AS Value, Entry_Data.DataTypeID AS DataTypeID
From Database.Entry
INNER JOIN Database.Data on Entry_Data.DataTypeID=DataTypeID
INNER Join Database.Data on Data.Value=Value
Please note that this is not an accurate example of the script its just for example purposes
Now i assume that i would create my function above this query and then add a where function below it.
The names of the columns and identifier are accurate.
You can use the case expression.
Your query is a little difficult to interpret intent, so I am going to make an assumption that you have two tables, (TableA and TableB) and you want to join one to the other like this: TableA.Value = TableB.Value, but TableB stores its Value column as a mixture of ints and hex(ints) where the hex(insts) are identified by value of TableB.VDataTypeID = 18 and anyt other DataTypeID indicates that TableB.Value a regular int.
If this is the case, to the following:
SELECT
...
FROM
TableA
INNER JOIN TableB ON TableA.Value
= CASE WHEN TableB.DataTypeID = 18 THEN Convert(...
ELSE TableB.DataTypeID
END
So you are using the CASE expression effectively as an in-place function on which to join.
It reads, Join TableA to TableB on the Values directly if TableB.DataTypeID is not 18, but if it is 18, then convert TableB.Value first and then do the join.
Hope this gives you what you need :-)

Joining Two Tables with Where Clause

I have two tables. Cat and Data.
Cat
Cat_Serno
Cat_Name
Data
Data_Serno
Data_Name
Data_Cat_ID
Data_Project_ID
When i Am doing a regular join I am getting
SELECT t1.*,t2.*
FROM Cat t1
LEFT JOIN Data t2 ON t1.Cat_Serno = t2.Data_Cat_Id
but when I apply a where condition on Project_Id it gives me only one column. I want to Display all the category and Null if there is no related data in the Data table along with the where clause on the Project_Id. It should also contain Null if I am using a where clause with a project_id without any value in the Data table (eg: where Project_Id=2) even if 2 is not present in the Data Table.
When I do it with Project_Id=2 which is not existing in Data Table I only get one Record with Null Values.
If you include column of table Data in where clause, your join will almost act as inner join, so if you want all records of Cat table, you should not include any column of Data table in where clause, still if you want to apply condition you can include it in "on" in join Try this,
SELECT t1.*,t2.*
FROM Cat t1
LEFT JOIN Data t2 ON t1.Cat_Serno = t2.Data_Cat_Id
and Project_Id=2
You have to add the where condition with the required values and add an OR condition with IS NULL
Example:
WHERE (DataName = 'Data_One' OR DataName IS NULL)
Please note, that NULL is not equals to any values (including NULL), so you have to handle it.
Another way:
WHERE COALESCE(DataName, 'n/a') IN ('Data_One', 'n/a')
If you want to return records from both Data and Cat, when there is no matching records in the opposite table, do a FULL OUTER JOIN, instead of a LEFT/RIGHT join.
Furthermore, to filter records from either table without filtering the entire result set, apply your conditions in the ON part of the statement, rather than the WHERE part of the statement. For example:
SELECT t1.*, t2.* FROM Cat t1 FULL OUTER JOIN Data t2
ON t1.Cat_Serno = t2.Data_Cat_Id
AND t2.Data_Project_Id = 2
Try:
WHERE t2.project_id = ...
OR t2.project_id IS NULL;

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.

Dynamic JOIN condition on a Table

I want to avoid string concatenation to create dynamic SQL query in SQL 2008.
How can I achieve the below functionality, if at all, efficiently ?
A table stores the various conditions a user had chosen to search DB by using one or more values to search tables from. For e.g. he can give SSN or DOB or both SSN and DOB.
So if he gives multiple values as input, then the query needs to find records matching ALL the criteria. This needs me to create queries from the below shown two tables
I always need to return personid, which may be from the person table, or the view.
Search conditions given by user will be stored in the 'conditions' table below
conditions
-------------
id,custid,dob,ssn,base
person
--------
id,firstname,ssn,dob
view
--------
id,personid,base
So, IF DOB is to be searched
SELECT p.personid from conditon c
INNER JOIN person p
ON p.dob=c.dob
WHERE c.condition=1
IF SSN and base is to be searched
SELECT v.personid from conditon c
INNER JOIN view v
ON c.base=v.base
INNER JOIN person p
ON p.ssn=c.ssn
WHERE c.condition=1
IF SSN,DOB and base is to be searched
SELECT v.personid from conditon c
INNER JOIN view v
ON c.base=v.base
INNER JOIN person p
ON p.ssn=c.ssn
AND
p.dob=c.dob
WHERE c.condition=1
Use the pattern below with IsNull() or Coalesce() function
Where ColumnName = IsNull(#InParameter, ColumnName)
or tyhe same pattern in a Join Condition
Join Table a
On [Other stuff]
And ColumnName = IsNull(#InParameter, ColumnName)
And then, if the parameter is supplied, the ql will filter or join based on the parameter value, if it not supplied or is null, the query will ignore it (ColumnValue = ColumnVale is always true (except for nullable columns)
EDITED: to add another predicate to Join Condition. because, in the case where you did not specifiy a parameter value, the join condition would always be true, and, unless some other predicate condition is in the join, you would effectively get a cartesian product...