How to join my tables with ID's that do not match - sql

I have these tables:
payments
| id | src_account | dest_account | payment_value |
+----+-------------+--------------+---------------+
| 1 | xxxxxxxxxxx | yyyyyyyyyyyy | 200 |
client_account
| client_id | account_id |
+-----------+-------------+
| 3 | xxxxxxxxxxx |
| 4 | yyyyyyyyyyy |
client
| id | firstname | lastname |
+----+-----------+------------+
| 3 | Sofia | Lenhark |
| 4 | Mark | Davoreski |
Now I need to select the following fields in a SQL Query:
Source Firstname
Source Lastname
Destination Firstname
Destination Lastname
Payment Value
I have tried the following:
SELECT
srcClientDetails.firstname,
srcClientDetails.lastname,
destClientDetails.firstname,
destClientDetails.lastname,
Payments.payment_value
FROM
dbo.payment AS Payments
LEFT JOIN dbo.client_account AS srcClientAccount ON Payments.src_account = srcClientAccount.account_id
LEFT JOIN dbo.client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
LEFT JOIN dbo.client_account AS destClientAccount ON Payments.dest_account = destClientAccount.account_id
LEFT JOIN dbo.client AS destClientDetails ON destClientAccount.client_id = destClientDetails.id
But this is returning only the payment value, without any other data.
Why aren't the other desired fields being returned?

Suggestions
(1) Try it in INNER JOIN
To check that the JOIN is correct (Values are equal),first test the query using INNER JOIN
SELECT *
FROM dbo.payment AS Payments
INNER JOIN dbo.client_account AS srcClientAccount ON Payments.src_account =
srcClientAccount.account_id
and check if it returns values or not, then add another table:
SELECT *
FROM dbo.payment AS Payments
INNER JOIN dbo.client_account AS srcClientAccount ON Payments.src_account =
srcClientAccount.account_id
INNER JOIN dbo.client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
And so on... This may leads you to the issue
(2) Account id difference due to collation or additional spaces
I think this will lead you to the problem, it may be caused due to a case sensitive collation or length sensitive or additional spaces. To diagnose this issue, you can also try converting both columns to same case and length and Trim additional spaces.
ON LTRIM(RTRIM(UPPER(CAST(Payments.src_account as varchar(50))))) = LTRIM(RTRIM(UPPER(CAST(srcClientAccount.account_id as varchar(50)))))
If this fixes the problem than it is better to edit the data (adding relations or constraints) rather than using this functions in the Join because it decrease the performance and doesn't use indexes.
(3) Create relations between tables
From the question it seems that there is no relation between columns, create the relations so values are constrained.

Your logic was right, just the [client_account].account_id was 1 'y' short for matching, or Payments.dest_account needs 1 less 'y'.
For example, you can see here I added 1 'y' to the [client_account].account_id and your query now returns the correct information:
WITH Payments AS (
SELECT '1' as id,
'xxxxxxxxxxx' as src_account,
'yyyyyyyyyyyy' as dest_account,
'200' as payment_value),
client_account AS (
SELECT '3' as client_id,
'xxxxxxxxxxx' as account_id
UNION ALL
SELECT '4' as client_id,
'yyyyyyyyyyyy' as 'account_id'), --added a 'y' here
client AS (
SELECT '3' as id,
'Sofia' as firstname,
'Lenhark' as lastname
UNION ALL
SELECT '4' as id,
'Mark' as firstname,
'Davoreski' as lastname)
SELECT
srcClientDetails.firstname,
srcClientDetails.lastname,
destClientDetails.firstname,
destClientDetails.lastname,
Payments.payment_value
FROM
payments AS Payments
LEFT JOIN client_account AS srcClientAccount ON Payments.src_account = srcClientAccount.account_id
LEFT JOIN client AS srcClientDetails ON srcClientAccount.client_id = srcClientDetails.id
LEFT JOIN client_account AS destClientAccount ON Payments.dest_account = destClientAccount.account_id
LEFT JOIN client AS destClientDetails ON destClientAccount.client_id = destClientDetails.id
Try it here

Related

How can I write a SQL join subquery to get the newest record for a relationship?

I have a SQL query for a Lansweeper report and I want to bring in the owner relationship, but I want to cover for cases when two relationships of the same type are written. I would like to return the most recently modified relationship.
SELECT tblAssets.AssetID,
tblAssetCustom.Serialnumber AS [Serial Number],
UPPER(tblAssets.AssetName) AS Name,
tblADusers.UPN AS [User]
FROM tblAssets
LEFT OUTER JOIN tblAssetCustom ON tblAssets.AssetID = tblAssetCustom.AssetID
LEFT OUTER JOIN tblAssetUserRelations ON tblAssets.AssetID = tblAssetUserRelations.AssetID
AND tblAssetUserRelations.Type = 1
LEFT OUTER JOIN tblADusers ON tblAssetUserRelations.Username = tblADusers.Username
WHERE (tblAssets.Assettype = - 1)
ORDER BY Name
Some records in this report are duplicated because they are being included. These assetUserRelations are also of Type = 1 but can be filtered by getting the most recent like below.
SELECT TOP (1) RelationID FROM tblAssetUserRelations order by Lastchanged desc
How can I add in a subquery that returns a user's UPN if there is a relationship of type=1 and get the most recent for any found relationships for the device?
I tried building a subquery join like this, but it returned only 1 user UPN for the entire query.
Left Join (Select *
From tblAssetUserRelations
Where tblAssetUserRelations.RelationID In (Select Top (1)
tblAssetUserRelations.RelationID
From tblAssetUserRelations Order By tblAssetUserRelations.Lastchanged
Desc)) As recentUserRelations On tblAssets.AssetID = recentUserRelations.AssetID
In my code from my top query I get a sample output like this because there are two entries in the tblAssetUserRelations table that have columns with tblAssetUserRelations.Type = 1 and tblAssetUserRelations.AssetID = 3730, but only one has a newer tblAssetUserRelations.Lastchanged value
| AssetID | Serial Number | Name | User |
| :-----: | :-----------: | :--------: | :--------------: |
|3730 |984621346we |harolddv-lpt|harold#example.com|
|3730 |984621346we |harolddv-lpt|thomas#example.com|
The expected output should look like this
| AssetID | Serial Number | Name | User |
| :-----: | :-----------: | :--------: | :--------------: |
|3730 |984621346we |harolddv-lpt|harold#example.com|

SQL Query : Facing issues to get desired records from different tables

I have two tables
Calendar (Calname, CCode, PCode)
Lookup (LCode, Name)
Calendar table contains records like,
Calname | CCode | PCode
abc | O_R | P_R
xyz | C_R | P_C
Lookup table contains records like,
LCode | Name
O_R | Reporting
C_R | Cross
P_R | Process
P_C | ProcessCross
I have to fetch the records in a way where I can get the name of all codes from lookup table which contains the record rowwise.
Desired Output,
Calname | CCode | PCode | CCodeName | PCodeName
abc | O_R | P_R | Reporting | Process
xyz | C_R | P_C | Cross | ProcessCross
I can not apply simply inner join on the basis of code it will not give me desired output.
I tried to use subquery also but it not worked out somehow,
.
Can anyone help me out with this issue.
Thanks
You can try joining the Calendar table to the Lookup table twice, using each of the two codes.
SELECT
c.Calname,
c.CCode,
c.PCode,
COALESCE(t1.Name, 'NA') AS CCodeName,
COALESCE(t2.Name, 'NA') AS PCodeName
FROM Calendar c
LEFT JOIN Lookup t1
ON c.CCode = t1.LCode
LEFT JOIN Lookup t2
ON c.PCode = t2.LCode
An alternative to Tim's answer would be to use scalar subqueries, which may or may not give you some performance benefit due to scalar subquery caching:
SELECT
c.Calname,
c.CCode,
c.PCode,
COALESCE((SELECT l1.name FROM lookup l1 WHERE c.ccode = l1.lcode), 'NA') AS CCodeName,
COALESCE((SELECT l2.name FROM lookup l2 WHERE c.pcode = l2.lcode), 'NA') AS PCodeName
FROM Calendar c;
I would test both answers to see which one works best for your data.

Select distinct of rows and show count of each value

I'm trying to select a distinct selection of [AssetManager].[AssetType] with a count of how many times the Id of an Asset Type is being referenced from table [AssetManager].[Asset]. Please see below for an example:
+-----------+-------------+
| Type Name | Asset Count |
+-----------+-------------+
| Phone | 5 |
| Desktop | 12 |
| Laptop | 22 |
+-----------+-------------+
However, the query I'm trying isn't working at all, the furthest I've got is selecting Asset titles with an inner join of their Type name (I'm not great at SQL...). Please see below for my current Query:
SELECT
[Asset].[Title] AssetTitle,
[AssetType].[Title] TypeTitle
FROM
[AssetManager].[Asset]
INNER JOIN
[AssetManager].[AssetType]
ON
[Asset].[AssetType_Id] = [AssetType].[Id]
As the comments said, all you needed to do is add a GROUP BY correctly:
SELECT
[AssetType].[Title] TypeTitle
, COUNT(*) [Asset Count]
FROM [AssetManager].[Asset]
INNER JOIN [AssetManager].[AssetType]
ON [Asset].[AssetType_Id] = [AssetType].[Id]
GROUP BY [AssetType].[Title]
Use OUTER APPLY to get reference count from [AssetManager].[Asset] table
SELECT
DISTINCT [AssetType].[Title] TypeTitle,
M.TypeCount
FROM
[AssetManager].[AssetType]
OUTER APPLY(
SELECT COUNT([Asset].[AssetType_Id]) AS TypeCount
FROM [AssetManager].[Asset]
WHERE [Asset].[AssetType_Id] = [AssetType].[Id]
)M

INNER JOIN Need to use column value twice in results

I've put in the requisite 2+ hours of digging and not getting an answer.
I'd like to merge 3 SQL tables, where Table A and B share a column in common, and Table B and C share a column in common--Tables A and C do not.
For example:
Table A - entity_list
entity_id | entity_name | Other, irrelevant columns
Example:
1 | Microsoft |
2 | Google |
Table B - transaction_history
transaction_id | purchasing_entity | supplying_entity | other, irrelevant columns
Example:
1 | 2 | 1
Table C - transaction_details
transactional_id | amount_of_purchase | Other, irrelevant columns
1 | 5000000 |
Using INNER JOIN, I've been able to get a result where I can link entity_name to either purchasing_entity or supplying_entity. And then, in the results, rather than seeing the entity_id, I get the entity name. But I want to substitute the entity name for both purchasing and supplying entity.
My ideal results would look like this:
1 [transaction ID] | Microsoft | Google | 5000000
The closes I've come is:
1 [transaction ID] | Microsoft | 2 [Supplying Entity] | 5000000
To get there, I've done:
SELECT transaction_history.transaction_id,
entity_list.entity_name,
transaction_history.supplying_entity,
transaction_details.amount_of_purchase
FROM transaction.history
INNER JOIN entity_list
ON transaction_history.purchasing_entity=entity_list.entity.id
INNER JOIN
ON transaction_history.transaction_id=transaction_details.transaction_id
I can't get entity_name to feed to both purchasing_entity and supplying_entity.
Here is the query:
SELECT h.transaction_id, h.purchasing_entity, purchaser.entity_name, h.supplying_entity, supplier.entity_name, d.amount_of_purchase
FROM transaction_history h
INNER JOIN transaction_details d
ON h.transaction_id = d.transaction_id
INNER JOIN entity_list purchaser
ON h.purchasing_entity = purchaser.entity_id
INNER JOIN entity_list supplier
ON h.supplying_entity = supplier.entity_id

SQL Order By Within A Count(Distinct)

I have the following tables:
filetype1
F1_ID | F1_ORDR | FILENAME
1 | 1 | file1.txt
2 | 2 | file2.txt
3 | 3 | file3.txt
4 | 2 | file4.txt
5 | 4 | file5.txt
filetype2
F2_ID | F2_ORDR | FILENAME
1 | 1 | file6.txt
2 | 2 | file7.txt
3 | 4 | file8.txt
ordr
OR_ID | OR_VENDOR
1 | 1
2 | 1
3 | 1
4 | 1
vendor
VE_ID | VE_NAME
1 | Company1
My goal is to have a list of vendors and a count of the number of orders where a file is connected for each type. For example, the end result of this data should be:
VENDOR | OR_CT | F1_CT | F2_CT
Company1 | 4 | 4 | 3
Because at least 1 type1 file was attached to 4 distinct orders and at least 1 type2 file was attached to 3 distinct orders. Currently my SQL code looks like this:
SELECT vendor.ve_id, vendor.ve_name,
(SELECT COUNT(or_id)
FROM ordr
WHERE ordr.or_vendor = vendor.ve_id) as OR_COUNT,
(SELECT COUNT(DISTINCT f1_order)
FROM filetype1 INNER JOIN ordr ON filetype1.f1_ordr = ordr.or_id
WHERE ordr.or_vendor = vendor.ve_id) as F1_CT,
(SELECT COUNT(DISTINCT f2_ordr)
FROM filetype2 INNER JOIN ordr ON filetype2.f2_ordr = ordr.or_id
WHERE ordr.or_vendor = vendor.ve_id) as F2_CT
FROM vendor
ORDER BY vendor.ve_name
Unfortunately this yields the following results:
VENDOR | OR_COUNT | F1_COUNT | F2_COUNT
Company1 | 4 | 5 | 3
My only guess is that because I'm using COUNT(DISTINCT) the COUNT is automatically assuming the DISTINCT is ordering by F1_ID instead of by F1_ORDR
If anyone can assist me on how to tell the COUNT(DISTINCT) to order by F1_ORDR that would be most helpful. I have searched the vast internet for a solution but its hard to explain what I want to a search engine, forums, etc. My database uses Microsoft SQL Server. My knowledge of database management is almost completely self taught, so I'm just glad I made it this far on my own. My expertise is in web design. Thank you for your time.
Your SQL yields the result you want for me.
Two pieces of advice
Order is a bad name for a table - it conflicts with a reserved word, and will cause you no end of hassle
You should join your tables like so
FROM filetype1
inner join [order]
on filetype1.f1_order = or_id
rather than using a where clause
Perhaps try this instead
select
vendor.VE_ID, vendor.VE_NAME,
count(distinct or_id),
count(distinct f1_order),
count(distinct f2_order)
from
vendor
left join [order]
on vendor.VE_ID = [order].OR_VENDOR
inner join filetype1
on [order].OR_ID = filetype1.F1_ORDER
left join filetype2
on [order].OR_ID = filetype2.F2_ORDER
group by
vendor.VE_ID, vendor.VE_NAME
Try this:
SELECT
vdr.VE_NAME
,COUNT(DISTINCT OR_ID) AS OR_ID
,COUNT(DISTINCT ft1.F1_ORDER) AS FT1_COUNT
,COUNT(DISTINCT ft2.F2_ORDER) AS FT2_COUNT
FROM
vendor vdr
LEFT OUTER JOIN [order] odr
ON vdr.VE_ID = odr.OR_VENDOR
INNER JOIN filetype1 ft1
ON odr.OR_ID = ft1.F1_ORDER
LEFT OUTER JOIN filetype2 ft2
ON odr.OR_ID = ft2.F2_ORDER
GROUP BY
vdr.VE_ID
,vdr.VE_NAME
I will propose you this:
Merge filetype1 and filetype2 tables in one table(filetype) and add another field named - f_type(for instance) of type INT or TINTYINT to store the filetype (1 or 2). This has the benefits of painlessly adding another filetype later
Now the query will look something like this:
SELECT
vendor.ve_name,
count(DISTINCT filetype.f_order),
filetype.f_type
FROM
filetype
INNER JOIN `order`
ON filetype.f_order = `order`.or_id
INNER JOIN vendor
ON `order`.or_vendor = vendor.ve_id
GROUP BY vendor.ve_id,filetype.f_type
This will give the count of orders for filetype.
For the total orders just add another query:
SELECT count(*) FROM `order`