Select field from table a if it exists, if it doesn't select field from table b - sql

SELECT a.amount, CASE When d.name <> NULL Then d.name Else c.name End As 'name'
from a
JOIN b on a.id= b.id
LEFT JOIN c on a.tokenId = c.tokenId
LEFT JOIN d on a.tokenId = d.tokenId
I'm attempting to select the name from table d if it exists, and if it doesn't, select it from table c. The name field comes back as NULL, however I know they are not null in either of the tables.
Can anyone help me get this solved?

You can't use the <> operator to compare with null. Use the is operator:
SELECT a.amount, CASE When d.name is not null Then d.name Else c.name End As 'name'
You can also use the coalesce function:
SELECT a.amount, coalesce(d.name, c.name) As 'name'

Use COALESCE:
SELECT a.amount, COALESCE(d.name,c.name) "name"
from a
JOIN b on a.id= b.id
LEFT JOIN c on a.tokenId = c.tokenId
LEFT JOIN d on a.tokenId = d.tokenId

Related

How can I show one element from one of two tables in a column

Table A has the id for a Company of which the name can be either in table B or table C.
What I'm trying to achieve is to show the fetched name in a new column, something like:
SELECT Bank.Name OR Company.Name AS 'CompanyName'
FROM Account
INNER JOIN Company
ON Account.CompanyID = Company.CompanyID OR
Account.CounterpartyID = Company.CompanyID
INNER JOIN Bank
ON Account.CompanyID = Bank.BankID OR
Account.CounterpartyID = Bank.BankID
WHERE ...
Can this work like this or do I need to use multiple SELECTs?
Thanks in advance!
Assumptions:
There will be ONE, or NO rows in TableA or TableB for the company
If there is a row in both TableA and TableB then taking the company name from TableA is acceptable
With those assumptions this code should do the trick:
SELECT A.CompanyId,
COALESCE(B.CompanyName, C.CompanyName)
FROM TableA A
LEFT
JOIN TableB B
ON A.CompanyId = B.CompanyId
LEFT
JOIN TableC C
ON A.CompanyId = C.CompanyId
WHERE TableA.CompanyId = 1234
Essentially what this code is doing is joining the tables together, using a LEFT JOIN so that rows from TableA don't get excluded by the absence of a row in either of TableB or TableC, then using COALESCE to get the first non-NULL value from either of the two tables for the CompanyName column.
The result of the query (if you were using SELECT *) where TableA doesn't contain a row would look a little like this:
Just to give an example of the data the query would be working against.
I would recommend LEFT JOIN. You seem to want names for both the company and the counterparty. That would be two columns and additional joins:
SELECT COALESCE(c.Name, b.Name) AS CompanyName,
COALESCE(cc.Name, bc.Name) AS CounterpartyName,
FROM Account a LEFT JOIN
Company c
ON a.CompanyID = c.CompanyID LEFT JOIN
Bank b
ON a.CompanyID = b.BankID AND
c.CompanyID IS NULL LEFT JOIN
Company cc
ON a.CounterpartyID = cc.CompanyID LEFT JOIN
Bank bc
ON a.CounterpartyID = bc.BankID AND
cc.CompanyID IS NULL
WHERE ...
SELECT
CASE
WHEN EXISTS(
SELECT b.name FROM tableB b WHERE b.name IS NOT NULL
) THEN b.name AS 'CompanyName'
WHEN EXISTS(
SELECT c.name FROM tableC c WHERE c.name IS NOT NULL
) THEN c.name AS 'CompanyName'
END
FROM tableA a
...
Hope this will work for you!
Yes, it can be done with COALESCE() function if you have NULLs, or even IIF() function or CASE expression
Instead of SELECT Bank.Name OR Company.Name AS 'CompanyName' you can do
SELECT COALESCE(Bank.Name, Company.Name) AS CompanyName
OR
SELECT IIF(Bank.Name IS NULL, Company.Name, Bank.Name) AS CompanyName
OR
SELECT CASE WHEN Bank.Name IS NULL
THEN Company.Name
ELSE Bank.Name
END AS CompanyName
If you mean '' then
SELECT CASE WHEN Bank.Name = ''
THEN Company.Name
ELSE Bank.Name
END AS CompanyName

SQL query with multiple joins a subqueries

I understand that a sql query cannot dynamically add and remove columns.
Every site will have the same extra data.
So what I need to do is get all the data from 'z' and tack on certain fields from linked tables.
Table tt_transaction and Table tt_extendeddatatype are independent.
tt_extendeddatadetail has 2 foreign keys.
1) fk-> tt_transaction.id
2) fk -> tt_extendeddatatype
I need to pull each transaction with its extended data. Each site will have the same extended data names.
I think the following broken code demonstrates what I am trying to do much better than I can explain.
SELECT z.*, aaa.name, aaa.value, bbb.name, bbb.value FROM tt_transaction
LEFT JOIN
(
SELECT a.name, a.description, b.value, b.transaction_id AS text FROM tt_extendeddatatype AS a
INNER JOIN tt_extendeddatadetail AS b ON a.id = b.type_id
WHERE a.name = 'Number'
) AS aaa
ON aaa.transaction_id = z.id
LEFT JOIN
(
SELECT a.name, a.description, b.value, b.transaction_id AS text FROM tt_extendeddatatype AS a
INNER JOIN tt_extendeddatadetail AS b ON a.id = b.type_id
WHERE a.name = 'STRING'
) AS bbb
ON bbb.transaction_id = z.id
My current error is column aaa.transaction_id does not exist
SELECT z.*, aaa.name, aaa.value, bbb.name, bbb.value FROM tt_transaction
LEFT JOIN
(
SELECT a.name, a.description, b.value, b.transaction_id AS transaction_id FROM tt_extendeddatatype AS a
INNER JOIN tt_extendeddatadetail AS b ON a.id = b.type_id
WHERE a.name = 'Number'
) AS aaa
ON aaa.transaction_id = z.id
LEFT JOIN
(
SELECT a.name, a.description, b.value, b.transaction_id AS text FROM tt_extendeddatatype AS a
INNER JOIN tt_extendeddatadetail AS b ON a.id = b.type_id
WHERE a.name = 'STRING'
) AS bbb
ON bbb.transaction_id = z.id
You named the column TEXT instead of transaction_id in your subquery.

Query is not returning any rows with like '%' operator and left outer join, if right table has no rows

I am using MS SQL SERVER 2008R2. i have two tables A and B as
create table A(
id int primary key, name Varchar(20));
create table B(
id int primary key, user_name Varchar(20));
insert into A values(1,'A1');
insert into A values(2,'A2');
insert into A values(3,'A3');
insert into A values(4,'A4');
insert into A values(5,'A5');
Now my problem is :
select A.*
from A left outer join B on A.id = B.id
where B.user_name like '%';
or
select A.*
from A left outer join B on A.id = B.id
where B.user_name like '%%';
Above written query does not return any records even though left table have 5 entries in it. without any filter on right table it works fine.
select A.* from A left outer join B on A.id = B.id
this query will give you out put like this...
id name id user_name
1 A1 NULL NULL
2 A2 NULL NULL
3 A3 NULL NULL
4 A4 NULL NULL
5 A5 NULL NULL
and you are comparing username using like with null
select A.* from A left outer join B on A.id = B.id where B.user_name like '%%';
hence it will not give you any output
you should try following query
select A.*,b.* from A left outer join B on A.id = B.id where (b.user_name like '%%' or b.user_name is null)
In your scenario...first left join is happening it is finding 5 entries and then on that record set sql sever is applying filter of user_name and as user_name for all rows is null..no records are getting displayed.
you can change your query to
select A.* from A left outer join B on A.id = B.id where ISNULL(B.user_name,'') like '%%';
You are using wild card for comparing null values as well,
Use this,
SELECT a.* FROM a LEFT OUTER JOIN b ON a.id = b.id WHERE b.user_name LIKE '%' OR b.user_name IS NULL;
Since all values in table B are NULL, any wildcard match on NULL values will return NULL.
So the condition where B.user_name like '%'; translates into where NULL like '%'; which evaluates to NULL as NULL cannot be compared with any value.
select A.* from A left outer join B on
A.id = B.id where COALESCE(B.user_name,'') like '%%';
select A.* from A left outer join B on
A.id = B.id where COALESCE(B.user_name,'') like '%';
supporting sql fiddle : http://sqlfiddle.com/#!6/1ca91/8
Note that the COALESCE is ANSI, and therefore supported in Oracle, SQL Server and PostGres and does shortcut evaluation. n
Edit: Based on new information that this same query should work in all SQL Server, PostGres and Oracle. I am changing the SQL query to
use COALESCE instead which is supported in all
Unless you use ISNULL() and check like this where
ISNULL(B.user_name,'') like '%';
select A.* from A left outer join B on
A.id = B.id where ISNULL(B.user_name,'') like '%%';
select A.* from A left outer join B on
A.id = B.id where ISNULL(B.user_name,'') like '%';
See this fiddle
http://sqlfiddle.com/#!6/1ca91/6
Please try this one:
select A.* from A
left outer join (SELECT * FROM B where user_name like '%') X on A.id = X.id;

Simulate a left join without using "left join"

I need to simulate the left join effect without using the "left join" key.
I have two tables, A and B, both with id and name columns. I would like to select all the dbids on both tables, where the name in A equals the name in B.
I use this to make a synchronization, so at the beginning B is empty (so I will have couples with id from A with a value and id from B is null). Later I will have a mix of couples with value - value and value - null.
Normally it would be:
SELECT A.id, B.id
FROM A left join B
ON A.name = B.name
The problem is that I can't use the left join and wanted to know if/how it is possible to do the same thing.
you can use this approach, but you must be sure that the inner select only returns one row.
SELECT A.id,
(select B.id from B where A.name = B.name) as B_ID
FROM A
Just reverse the tables and use a right join instead.
SELECT A.id,
B.id
FROM B
RIGHT JOIN A
ON A.name = B.name
I'm not familiar with java/jpa. Using pure SQL, here's one approach:
SELECT A.id AS A_id, B.id AS B_id
FROM A INNER JOIN B
ON A.name = B.name
UNION
SELECT id AS A_id, NULL AS B_id
FROM A
WHERE name NOT IN ( SELECT name FROM B );
In SQL Server, for example, You can use the *= operator to make a left join:
select A.id, B.id
from A, B
where A.name *= B.name
Other databases might have a slightly different syntax, if such an operator exists at all.
This is the old syntax, used before the join keyword was introduced. You should of course use the join keyword instead if possible. The old syntax might not even work in newer versions of the database.
I can only think of two ways that haven't been given so far. My last three ideas have already been given (boohoo) but I put them here for posterity. I DID think of them without cheating. :-p
Calculate whether B has a match, then provide an extra UNIONed row for the B set to supply the NULL when there is no match.
SELECT A.Id, A.Something, B.Id, B.Whatever, B.SomethingElse
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN 1
ELSE 0
END Which
FROM A
) A
INNER JOIN (
SELECT 1 Which, B.* FROM B
UNION ALL SELECT 0, B* FROM B WHERE 1 = 0
) B ON A.Which = B.Which
AND (
A.Which = 0
OR (
A.Which = 1
AND A.Id = b.Id
)
)
A slightly different take on that same query:
SELECT A.Id, B.Id
FROM
(
SELECT
A.*,
CASE
WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN A.Id
ELSE -1 // a value that does not exist in B
END PseudoId
FROM A
) A
INNER JOIN (
SELECT B.Id PseudoId, B.Id FROM B
UNION ALL SELECT -1, NULL
) B ON A.Which = B.Which
AND A.PseudoId = B.PseudoId
Only for SQL Server specifically. I know, it's really a left join, but it doesn't SAY LEFT in there!
SELECT A.Id, B.Id
FROM
A
OUTER APPLY (
SELECT *
FROM B
WHERE A.Id = B.Id
) B
Get the inner join then UNION the outer join:
SELECT A.Id, B.Id
FROM
A
INNER JOIN B ON A.name = B.name
UNION ALL
SELECT A.Id, NULL
FROM A
WHERE NOT EXISTS (
SELECT *
FROM B
WHERE A.Id = B.Id
)
Use RIGHT JOIN. That's not a LEFT JOIN!
SELECT A.Id, B.Id
FROM
B
RIGHT JOIN A ON B.name = A.name
Just select the B value in a subquery expression (let's hope there's only one B per A). Multiple columns from B can be their own expressions (YUCKO!):
SELECT A.Id, (SELECT TOP 1 B.Id FROM B WHERE A.Id = B.Id) Bid
FROM A
Anyone using Oracle may need some FROM DUAL clauses in any SELECTs that have no FROM.
You could use subqueries, something like:
select a.id
, nvl((select b.id from b where b.name = a.name), "") as bId
from a
you can use oracle + operator for left join :-
SELECT A.id, B.id
FROM A , B
ON A.name = B.name (+)
Find link :-
Oracle "(+)" Operator
SELECT A.id, B.id
FROM A full outer join B
ON A.name = B.name
where A.name is not null
I'm not sure if you just can't use a LEFT JOIN or if you're restricted from using any JOINS at all. But as far as I understand your requirements, an INNER JOIN should work:
SELECT A.id, B.id
FROM A
INNER JOIN B ON A.name = B.name
Simulating left join using pure simple sql:
SELECT A.name
FROM A
where (select count(B.name) from B where A.id = B.id)<1;
In left join there are no lines in B referring A so 0 names in B will refer to the lines in A that dont have a match
+ or A.id = B.id in where clause to simulate the inner join

select row from table and substitute a field with one from another column if it exists

I'm trying construct a PostgreSQL query that does the following but so far my efforts have been in vain.
Problem:
There are two tables: A and B. I'd like to select all columns from table A (having columns: id, name, description) and substitute the "A.name" column with the value of the column "B.title" from table B (having columns: id, table_A_id title, langcode) where B.table_A_id is 5 and B.langcode is "nl" (if there are any rows).
My attempts:
SELECT A.name,
case when exists(select title from B where table_A_id = 5 and langcode= 'nl')
then B.title
else A.name
END
FROM A, B
WHERE A.id = 5 and B.table_A_id = 5 and B.langcode = 'nl'
-- second try:
SELECT COALESCE(B.title, A.name) as name
from A, B
where A.id = 5 and B.table_A_id = 5 and exists(select title from B where table_A_id = 5 and langcode= 'nl')
I've tried using a CASE and COALESCE() but failed due to my inexperience with both concepts.
Thanks in advance.
araqnid's is the answer you are looking for, I bet.
But if you want to enforce that no more than one row is returned for each original matching A row, you might prefer to do a subselect instead of a LEFT JOIN. For example:
SELECT A.id, COALESCE(
( SELECT max(B.title) FROM B WHERE
langcode = 'nl' AND B.table_a_id = A.id), A.name ) as name
FROM A
WHERE A.id = 5
I use "max" here to select an arbitrary value, in the event there is more than one. You can use "min" or whatever you consider appropiate in your case.
Perhaps this is more easy to understand than the LEFT JOIN, but (apart from the two being not exactly equivalent) a JOIN will perform better than N subselects (much better is N is large).
Anyway, from a learning point of view, it's good to understand both.
select A.id, coalesce(B.title, A.name)
from TableA AS A
left join (select table_a_id, title from TableB where langcode = 'nl') AS B
on B.table_a_id = A.id
WHERE A.id = 5
Ok, I'm not sure how your tables have to be joined, but something like this should do the job:
SELECT yourcolumnlist,
CASE WHEN A.name IS NULL THEN B.title ELSE A.name END
FROM TableA AS A
INNER JOIN TableB AS B
ON A.id = B.table_A_id
WHERE B.table_A_id = 5
AND B.langcode = 'nl'
Another way to do it would be to use the COALESCE() function:
SELECT yourcolumnlist,
COALESCE(A.name, B.title)
FROM TableA AS A
INNER JOIN TableB AS B
ON A.id = B.table_A_id
WHERE B.table_A_id = 5
AND B.langcode = 'nl'
Try this
select A.id,B.title,A.description from TableA as A inner join tableB as B
on A.id=B.id where B.table_A_id = 5 and B.langcode ='nl'