Selecting full names of pairs of ISO-coded countries - sql

Suppose I have got two tables, one of which is named A and contains two columnsĀ : country1 (as an ISO code), country2 (as an ISO code) whilst the other one is named B and contains two columnsĀ : code (ISO code of country) and name (full name of country).
I would like to list all pairs of countries that occur in table A using their full names, rather than their ISO codes.
If I had to get the full name of every country that occurs in the first column of table A, I would write te following:
SELECT name AS name1
FROM B
INNER JOIN A ON B.code = A.country1
However, I am struggling to find out how to get both columns with full names.

You should be able to join the code column from B on both the country1 and country2 columns from A. You just need to make sure you alias it differently on each join.
SELECT A.country1, A.country2, B1.name AS name1, B2.name as name2
FROM A
JOIN B AS B1 ON B1.code = A.country1
JOIN B AS B2 ON B2.code = A.country2

Join should always be on same column type from both tables. Isnull will work for you, If country codes are stored in different columns in TableA
SELECT name AS name1
FROM B
INNER JOIN A ON B.code = isnull(A.country1, a.Country2)
or Use case statement
SELECT name AS name1
FROM B
INNER JOIN A ON B.code = case when A.country1 is null then A.country2
else A.country1 end

Related

show different columns from different table with inner join

Hi i have a lot of inner in a query but i can't print column in different table, for example:
where
Table A
id f
-----------
xxx gggg
bbb kkkk
Table B
name code
-----------
ccc dddd
bbb oooo
My code:
select A.id,A.F from (query1)as stima
join
(select B.name,B.code from B as aaaa query)as noome
on noome.code=stima.F;
But if i want put name columns of B table in 'select A.id,A.F' how can i do?
My output is id and colum F but i want output: id,F and name columns.
Any time you have a column in an inner query that you want to use in an outer query, you have to make sure the inner query selects it. It will then become part of the query block with the new alias you give it:
SELECT
a.Name,
a.SomethingElse,
b.ColumnX,
b.ColumnYYY
FROM
(
SELECT c.Name, d.SomethingElse FROM c JOIN d ON ..
) a
JOIN
(
SELECT e.ColumnX, f.ColY as ColumnYYY FROM e JOIN f ON ..
) b
When they're in the inner queries the columns are like d.SomethingElse and f.ColY but when they pass outside of those brackets, they get a new alias, because they are part of the data block that is aliased by a or b, so you no longer refer to them as their inner names.. Particularly in the case of f.ColY it was renamed to ColumnYYY and also given a new "table" alias of b..
You can use any columns from the tables of the from clause.
I think you need this:
select A.id,A.F, noome.name -- this
from (query1)as stima
join
(select B.name,B.code from B as aaaa query)as noome
on noome.code=stima.F;

JOIN query, SQL Server is dropping some rows of my first table

I have two tables customer_details and address_details. I want to display customer details with their corresponding address, so I was using a LEFT JOIN, but when I'm executing this query, SQL Server drops rows where street_no of customer_details table doesn't match with the street_no in address_detials table and displays only rows where `street_no' of customer_detials = street_no of address_details table. I need to display a complete customer_details table and in case if street_no doesn't matches it should display empty string or anything. Am I doing anything wrong in my SQL join?
Table customer_details:
case_id customer_name mob_no street_no
-------------------------------------------------
1 John 242342343 4324234234234
1 Rohan 343233333 43332
1 Ankit 234234233 2342332423433
1 Suresh 234234324 2342342342342
1 Ranjeet 343424323 32233
1 Ramu 234234333 2342342342343
Table address_details:
s_no streen_no address city case_id
------------------------------------------------------
1 4324234234234 Roni road Delhi 1
2 2342332423433 Natan street Lucknow 1
3 2342342342342 Koliko road Herdoi 1
SQL JOIN query:
select
a.*, b.address
from
customer_details a
left join
address_details b on a.street_no = b.street_no
where
b.case_id = 1
Now that it became clear that you used b.case_id=1, I will explain why it filters:
The LEFT JOIN itself returns some rows that contain all NULL values for table b in the result set, which is what you want and expect.
But by using WHERE b.case_id=1, the rows containing NULL values for table b are filtered out because none of them matches the condition (all those rows have b.case_id=NULL so they don't match).
It might work to instead use WHERE a.case_id=1, but we don't know if a.case_id and b.case_id are always the same value for matching rows (they might not be; and if they are always the same, then we just identified a potential redundancy).
There are two ways to fix this for sure.
(1) Move b.case_id = 1 into the left join condition:
left join address_details b on a.street_no = b.street_no and b.case_id = 1
(2) Keep b.case_id = 1 in the WHERE but also allow for NULLED-out b values:
left join address_details b on a.street_no = b.street_no
where b.case_id = 1
or b.street_no IS NULL
Personally I'd go for (1) because that is the most clear way to express that you want to filter b on two conditions, without affecting the rows of a that are being returned.
I do think that Wilhelm Poggenpohl answer is kind of right. You just need to change the last join condition a.case_id=1 to b.case_id=1
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and b.case_id=1
This query will show every row from customer_details and the corresponding adress if there is a match of street_no and the adress meets the condition case_id=1.
This is because of the where clause. Try this:
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and a.case_id=1

Joining tables based on value

I'm having some hard time doing the join function on those two tables. I have simplified the example dataset as there are additional where-clauses involved for the first table however that doesn't seem to be a problem.
I would write the query for joining the two tables below:
select a.prod_code, a.prod_name, b.ref_value from Product_code a
left join Product_reference b on a.prod_code = b.pref_code
where a.prod_code <> 'CURTAIN' and b.ref_value = 'MAN'
The problem I'm facing is that I want to join tables kind of conditionally. I.e. if the ref_type value is 'MAN' in Product_reference table, I do want to join it, otherwise not.
For an example this query would not include "Chair" in the result as it does not have an ref_type 'MAN' available in the "Product_name". What I'd need though is still show it in the query result, just without joined value from the Product_reference table (given that value with ref_type 'MAN' does not exist for it), not leave it out altogether.
Meanwhile Product_name table record 'CURTAIN' should be left off (regardless if Product_reference ref_type 'MAN' exists or not)
Any recommendations?
Product_code
prod_code prod_name
A Table
B Chair
C Window
D Door
E Curtain
Product_reference
pref_code ref_type ref_value
A MAN x
A AUTO y
B AUTO z
C AUTO z1
C MAN x1
D AUTO zxc
E AUTO abc
E MAN cba
Move b.ref_value = 'MAN' to the join predicate:
SELECT a.prod_code, a.prod_name, b.ref_value
FROM Product_code a
LEFT JOIN Product_reference b ON a.prod_code = b.pref_code AND b.ref_value = 'MAN'
WHERE a.prod_code <> 'CURTAIN'
This will accomplish what you want, which is only left joining the data from table b where b.ref_value = 'MAN', instead of removing all other rows from the result set altogether.
Side note, thanks for including your query and sample data in your very well made question. We appreciate it.
you could use a inner join on the distinct product that have 'MAN'
select
a.prod_code
, a.prod_name
, b.ref_value
from Product_code a
inner join (
select distinct pref_code
from Product_reference
where ref_type = 'MAN') t2 on t2.pref_code = a.prod_code
and a.prod_code <> 'CURTAIN'

Find which rows have different values for a given column in Teradata SQL

I am trying to compare two addresses from the same ID to see whether they match. For example:
Id Adress Code Address
1 1 123 Main
1 2 123 Main
2 1 456 Wall
2 2 456 Wall
3 1 789 Right
3 2 100 Left
I'm just trying to figure out whether the address for each ID matches. So in this case I want to return just ID 3 as having a different address for Address Code 1 and 2.
Join the table with itself and give it two different aliases (A and B in the following example). This allows to compare different rows of the same table.
SELECT DISTINCT A.Id
FROM
Address A
INNER JOIN Address B
ON A.Id = B.Id AND A.[Adress Code] < B.[Adress Code]
WHERE
A.Address <> B.Address
The "less than" comparison < ensures that you get 2 different addresses and you don't get the same 2 address codes twice. Using "not equal" <> instead, would yield the codes as (1, 2) and (2, 1); each one of them for the A alias and the B alias in turn.
The join clause is responsible for the pairing of the rows where as the where-clause tests additional conditions.
The query above works with any address codes. If you want to compare addresses with specific address codes, you can change the query to
SELECT A.Id
FROM
Address A
INNER JOIN Address B
ON A.Id = B.Id
WHERE
A.[Adress Code] = 1 AND
B.[Adress Code] = 2 AND
A.Address <> B.Address
I imagine that this might be useful to find customers having a billing address (Adress Code = 1 as an example) differing from the delivery address (Adress Code = 2) .
This works for PL/SQL:
select count(*), id,address from table group by id,address having count(*)<2
You can do this using a group by:
select id, addressCode
from t
group by id, addressCode
having min(address) <> max(address)
Another way of writing this may seem clearer, but does not perform as well:
select id, addressCode
from t
group by id, addressCode
having count(distinct address) > 1
Personally, I would print them to a file using Perl or Python in the format
<COL_NAME>: <COL_VAL>
for each row so that the file has as many lines as there are columns. Then I'd do a diff between the two files, assuming you are on Unix or compare them using some equivalent utilty on another OS. If you have multiple recordsets (i.e. more than one row), I would prepend to each file row and then the file would have NUM_DB_ROWS * NUM_COLS lines

Most efficient way to join fields in a dynamic table structure

We have three tables storing document information that I'll call table A, B, and C. Table A stores the main fields for said documents (such as the file name and size and other general information). In order to dynamically add new fields, we use Table B to store a list of new fields and their data types(determined by an enumeration), and Table C to store the values for those fields.
Table A
ID - PK int
FieldX...
FieldY...
FieldZ...
Table B
Id - PK int
Name - nvarchar(max)
Type - int
Table C
Id - PK int
AId - FK to table A int
BId - FK to table B int
Value - nvarchar(max)
What we want to do as efficiently as possible is to pull the values from table C as an additional column in a query from table A. Right now here is how I'm doing it for each extra field in Table B.
select (select c.value
from B b, C c
where c.AId = a.Id
and c.Bid = b.Id
and b.Name = 'Dynamic Field Name') As 'Dynamic Field Name'
From A a
We have a database with Table A filled with 36000 rows. For each additional dynamic field that is added to the query, its adding about 4 seconds to the total time to finish the query, making a query that contains 10 dynamic fields take at least 40 seconds. Realistically, we want any query to finish in under 10. Is there any way to write this more efficiently?
First of all your query may give you errors because you have not defined C.(A+B) as unique. If there are multiple values per A+B combination in C, it causes the subquery to fail with
Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value.
Assuming it is unique, then you should be safe to just LEFT JOIN them together to make use of SET-based operations.
select a.*,
c1.value [Dynamic Field Name 1],
c2.value [Dynamic Field Name 2]
From A a
JOIN B b1 on b1.Name = 'Dynamic Field Name1'
LEFT JOIN C c1 on c1.AId = a.Id and c.Bid = b1.Id
JOIN B b2 on b2.Name = 'Dynamic Field Name2'
LEFT JOIN C c2 on c2.AId = a.Id and c2.Bid = b2.Id
Using a subquery at the SELECT level forces each record, and each dynamic field to execute as a mini-select = very slow.
Perhaps a query like this would work as well:
select a.id
,MAX(CASE WHEN b.Name = 'Dynamic Field Name' THEN c.value END) As Dynamic_Field_Name
,MAX(CASE WHEN b.Name = 'Dynamic Field Name 2' THEN c.value END) As Dynamic_Field_Name2
from A a, B b, C c
where c.AId = a.Id
and c.Bid = b.Id
and b.Name IN ('Dynamic Field Name', 'Dynamic Field Name 2')
group by a.id
Same idea, you only want to make one pass through the table, rather than a lookup for each row. The aggregate is to compress the sparse matrix into a single row (ie there will only by one dynamic field value in a row, each row having a different column with a value). Don't know how it would perform though.