Simplify multiple joins - sql-server

I have a Claims table with 70 columns, 16 of which contain diagnosis codes. The codes mean nothing, so I need to pull the descriptions for each code located in a separate table.
There has to be a simpler way of pulling these code descriptions:
-- This is the claims table
FROM
[database].[schema].[claimtable] AS claim
-- [StagingDB].[schema].[Diagnosis] table where the codes located
-- [ICD10_CODE] column contains the code
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag1 ON claim.[ICDDiag1] = diag1.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag2 ON claim.[ICDDiag2] = diag2.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag3 ON claim.[ICDDiag3] = diag3.[ICD10_CODE]
-- and so on, up to ....
LEFT JOIN
[StagingDB].[schema].[Diagnosis]AS diag16 ON claim.[ICDDiag16] = diag16.[ICD10_CODE]
-- reported column will be [code_desc]
-- ie:
-- diag1.[code_desc] AS Diagnosis1
-- diag2.[code_desc] AS Diagnosis2
-- diag3.[code_desc] AS Diagnosis3
-- diag4.[code_desc] AS Diagnosis4
-- etc.

I think what you are doing is already correct in given scenario.
Another way can be from programming point of view or you can give try and compare ther performace.
i) Pivot Claim table on those 16 description columns.
ii) Join the Pivoted column with [StagingDB].[schema].[Diagnosis]
Another way can be to put [StagingDB].[schema].[Diagnosis] table in some #temp table
instead of touching large Staging 16 times.
But for data analysis has to be done to decide if there is any way.

You can go for UNPIVOT of the claimTable and then join with Diagnosis table.
TEST SETUP
create table #claimTable(ClaimId INT, Diag1 VARCHAR(10), Diag2 VARCHAR(10))
CREATE table #Diagnosis(code VARCHAR(10), code_Desc VARCHAR(255))
INSERT INTO #ClaimTable
VALUES (1, 'Fever','Cold'), (2, 'Headache','toothache');
INSERT INTO #Diagnosis
VALUEs ('Fever','Fever Desc'), ('cold','cold desc'),('headache','headache desc'),('toothache','toothache desc');
Query to Run
;WITH CTE_Claims AS
(SELECT ClaimId,DiagnosisNumeral, code
FROM #claimTable
UNPIVOT
(
code FOR DiagnosisNumeral in ([Diag1],[Diag2])
) as t
)
SELECT c.ClaimId, c.code, d.code_Desc
FROM CTE_Claims AS c
INNER JOIN #Diagnosis as d
on c.code = d.code
ResultSet
+---------+-----------+----------------+
| ClaimId | code | code_Desc |
+---------+-----------+----------------+
| 1 | Fever | Fever Desc |
| 1 | Cold | cold desc |
| 2 | Headache | headache desc |
| 2 | toothache | toothache desc |
+---------+-----------+----------------+

Related

what to use instead of union to join same results based on two where clauses

I have two queries that work as expected for example
Query 1
select Name,ID,Product,Question
from table 1
where Id= 9 and ProductID=30628
table output
Name | ID | Product | QUestion
0659e103-b33d-4603 |12356|Apple | is it picked up?
0659e103-b33d-4603 |12456|Apple |Available in store?
0659e103-b33d-4603 |12458|Apple |confirm order?
query 2
select Name,ID,Product,Question
from table 1
where Id= 9 and TypeID=2
table output
Name | ID | Product | QUestion
0659e103-b33d-4603 |12347|Apple | Problem at store?
as you can see in query 1 i use a ProductID and in query 2 i use a TypeID these two values gives me different out puts
so i used a union to join both as follows
select Name,ID,Product,Question
from table 1
where Id= 9 and ProductID=30628
union
select Name,ID,Product,Question
from table 1
where Id= 9 and TypeID=2
which i get the desired output
Name | ID | Product | QUestion
0659e103-b33d-4603 |12356|Apple | is it picked up?
0659e103-b33d-4603 |12456|Apple |Available in store?
0659e103-b33d-4603 |12458|Apple |confirm order?
0659e103-b33d-4603 |12347|Apple | Problem at store?
is their a better way to do this because my query will grow and i would not like to repeat the same thing over again. is their a better way to optimize the query?
NOte i can not use ProductID and TypeID on the same line because they do not result in accurate results
You could use OR since you are querying the same table.
SELECT Name
,ID
,Product
,Question
FROM TABLE1
WHERE (
Id = 9
AND ProductID = 30628
)
OR (
Id = 9
AND TypeID = 2
)
If you have a growing number of OR conditions you could use a temp table/variable and inner join to profit from a set based operation.
The inner join will only return matching rows.
CREATE TABLE #SomeTable(Id INT NOT NULL, ProductID INT NULL, TypeID INT NULL)
-- Insert all conditions you want to match.
INSERT INTO #SomeTable(Id, ProductID, TypeId)
VALUES (9, 30628, NULL)
, (9, NULL, 2)
SELECT Name
,ID
,Product
,Question
FROM TABLE1 x
INNER JOIN #SomeTable y ON
x.ID = y.ID -- Since ID is Not null in the temp table
AND (y.ProductID IS NULL OR y.ProductID = x.ProductID)
AND (y.TypeID IS NULL OR y.TypeID = x.TypeID)
You can use cas-when clause with a self join.
Case-when something like this:
SELECT t1_2.Name,
t1_2.ID,
t1_2.Product,
t1_2.Question,
(CASE WHEN (t1.Id= 9 and t1.ProductID=30628) THEN ID
WHEN (t1.Id= 9 and t1.TypeID=2) THEN ID
ELSE NULL) AS IDcalc
FROM table_1 t1 LEFT JOIN table_1 t1_2
ON t1.ID = t1_2.ID
WHERE (CASE WHEN (t1.Id= 9 and t1.ProductID=30628) THEN ID
WHEN (t1.Id= 9 and t1.TypeID=2) THEN ID
ELSE NULL) IS NOT NULL
You can use any table in the join.
In comparison of query performance the OR is much better until you have only one table, if you have more tables, then you should use temp table or case-when in your query.

How to split a sql table into two tables using a third table containing reference values

I am new here and new to sql therefore I hope I am asking the the question correct.
table internal product EAN
EAN/UPC
1234567789
2233445566
table shop sales
EAN/UPC | product | sales value |
1234567789 | xyz | 200 |
2233445566 | abc | 100 |
9685444444 | yyy | 150 |
Result should look like:
table my company sales
EAN/UPC | product | sales value |
1234567789 | xyz | 200 |
2233445566 | abc | 100 |
and
table my competitor sales
EAN/UPC | product | sales value |
9685444444 | yyy | 150 |
I have all my EAN/UPC codes available (about 100.000)
I am receiving the sales data from the shop including competitor EAN/UPC codes which I need to seperate from mine. I would like to use the first table as reference and if move the values where the EAN/UPC match into the table my company sales, the others where there is no matching EAN/UPC into the table my competitors sales.
I was thinking about using a select into statement with the condition where EAN/UPC T1 is not EAN/UPC T2 .
Thank you very much for your help.
Select *
into CompanySales
from ShopSales
where [EAN/UPC] in (select [EAN/UPC] from productEAN);
Select *
into CompetitorSales
from ShopSales
where [EAN/UPC] not in (select [EAN/UPC] from productEAN);
This should work out:
Setup (for testing purposes) using CTE:
WITH [shop sales] ([EAN/UPC], [product], [sales value]) AS (
SELECT * FROM (
VALUES
(1234567789,'xyz',200),
(2233445566,'abc',100),
(9685444444,'yyy',150)
) AS A (Column1, Column2, Column3)
),
[internal product EAN] ([EAN/UPC]) AS (
SELECT * FROM (
VALUES
(1234567789),
(2233445566)
) AS A (Column1)
)
Two queries to pull the information:
SELECT s.*
FROM [internal product EAN] ip
INNER JOIN [shop sales] s ON ip.[EAN/UPC] = s.[EAN/UPC]
SELECT s.*
FROM [shop sales] s
WHERE s.[EAN/UPC] NOT IN (SELECT [EAN/UPC] FROM [internal product EAN])
As far as creating tables from the data, an INSERT INTO or a SELECT INTO for a new table would probably suffice.
Try something like this:
INSERT INTO OnlyMyProductSales([EAN],[product],SalesValue)
SELECT s.*
FROM [MyProduct] p
INNER JOIN [AllSales] s
ON p.[EAN] = s.[EAN]
INSERT INTO MyCompetitionSales([EAN],[product],SalesValue)
SELECT s.*
FROM [AllSales] s
LEFT JOIN [MyProduct] p
ON p.[EAN] = s.[EAN]
WHERE s.[EAN] IS NULL
this will help:
CREATE TABLE #internalproductEAN (EAN_UPC VARCHAR(50))
INSERT INTO #internalproductEAN
SELECT 1234567789 UNION ALL
SELECT 2233445566
CREATE TABLE #shopsales (EAN_UPC VARCHAR(50),product VARCHAR(10),SalesValue BIGINT)
INSERT INTO #shopsales
SELECT '1234567789','xyz',200 UNION ALL
SELECT '2233445566','abc',100 UNION ALL
SELECT '9685444444','yyy',150
CREATE TABLE #companysales (EAN_UPC VARCHAR(50),product VARCHAR(10),SalesValue BIGINT)
INSERT INTO #companysales
SELECT ss.* FROM #shopsales ss
INNER JOIN #internalproductEAN ip ON ss.EAN_UPC=ip.EAN_UPC
SELECT * FROM #companysales
CREATE TABLE #competitorsales (EAN_UPC VARCHAR(50),product VARCHAR(10),SalesValue BIGINT)
INSERT INTO #competitorsales
SELECT ss.* FROM #shopsales ss
LEFT JOIN #internalproductEAN ip ON ss.EAN_UPC=ip.EAN_UPC
WHERE ip.EAN_UPC IS NULL
SELECT * FROM #competitorsales
--SELECT * FROM #internalproductEAN
--SELECT * FROM #shopsales
DROP TABLE #internalproductEAN
DROP TABLE #shopsales
DROP TABLE #companysales
DROP TABLE #competitorsales

Adding constant in the results from a multiple SQL Server join

I have four tables to join and I need to identify which table the data is coming from in a column within the results. I join Tbl1 to Tbl2 using left outer join. I join Tbl1 to Tbl3 using left outer join and same with Tbl1 to Tbl 4. SerialNo is the key field I join all tables by. The results needs to indicate which table the data came from. For matching results between tables I want the right table to be identified. For example, in my sample tables I want to show that Tbl2 is in the results for those records where SerialNo is ABC123, DEF987 and HJK321.
Because of how the data will be extract from the database I'm unable to initiate a stored procedure so I'm planning on having a view to pull the data from, unless I can utilize a temp table in the process.
Tbl1
*Hostname* | *SerialNo*
Laptop1 | ABC123
Laptop2 | DEF987
Desktop1 | WER987
Desktop2 | YRT848
Desktop3 | YTT876
Laptop2 | HJK321
Tbl2
*Location* | *SerialNo*
MS | ABC123
CO | DEF987
CA | ZYC342
AZ | XYZ789
IN | HJK321
What I'd like to see in the results...
Result1
*Hostname* | *SerialNo* |*Location* |*RecordOrigin*
Laptop1 | ABC123 |MS |Tbl2
Laptop2 | DEF987 |CO |Tbl2
Desktop1 | WER987 |NULL |Tbl1
Desktop2 | YRT848 |NULL |Tbl1
Desktop3 | YTT876 |NULL |Tbl1
Laptop2 | HJK321 |IN |Tbl2
I tried creating an additional table for RecordOrigin information, but I wasn't able to join to the other tables correctly.
I'm should also note that I'm not able to edit the data in, or change the structure of, the source tables tables (i.e. Tbl1, Tbl2, etc.).
You can use a case expression to see if a table is returning a column or not like so:
select
t.Hostname
, t.SerialNo
, l.Location
, RecordOrigin = case
when l.SerialNo is not null
then 'Tbl2'
else 'Tbl1'
end
from Tbl1 as t
left join Tbl2 as l
on t.SerialNo = l.SerialNo
I think I might have figured it out by UNION the tables and using DISTINCT and MAX to remove duplication.
SELECT DISTINCT Hostname, MAX(SerialNo), MAX(Location), RecordOrigin
FROM
(
SELECT Hostname, SerialNo, Location, 'Tbl1' AS RecordOrigin
FROM Tbl1
UNION
SELECT Hostname, SerialNo, Location, 'Tbl2' AS RecordOrigin
FROM Tbl1
)
GROUP BY Hostname, RecordOrigin

Find one record that exists as two records in another vendor database

I have two vendor databases that have become horribly out-of-sync over the years that I'm trying to correct. A single customer can have multiple id_numbers, and these IDs exist in both vendor databases. All of the IDs for a single customer are correctly attached to one customer record in the Vendor1 database (meaning they belong to the same customer_code). The problem, however, is that those same IDs might be split amongst multiple customers in the Vendor2 database, which is incorrect. I will need to merge those multiple customers together in the Vendor2 database.
I'm trying to identify which customers are represented as two or more customers in the second vendor database. So far I have joined the two together, but I can't figure out how to find only customers that having two or more distinct MemberInternalKeys for the same customer_code.
Here's what I have so far:
select top 10
c.customer_code,
i.id_number,
cc.MemberInternalKey
from Vendor1.dbo.customer_info as c
join Vendor1.dbo.customer_ids as i
on c.customer_code = i.customer_code
join Vendor2.dbo.Clubcard as cc
on (i.id_number collate Latin1_General_CI_AS_KS) = cc.ClubCardId
where i.id_code = 'PS'
In the example below, I would expect to only get back the last two rows in the table. The first two rows should not be included in the results because they have the same MemberInternalKey for both records and belong to the same customer_code. The third row should also not be included since there is a 1-1 match between both vendor databases.
customer_code | id_number | MemberInternalKey
--------------|-----------|------------------
5549032 | 4000 | 4926877
5549032 | 4001 | 4926877
5031101 | 4007 | 2379218
2831779 | 4029 | 1763760
2831779 | 4062 | 4950922
Any help is greatly appreciated.
If I understand correctly, you can use window functions for this logic:
select c.*
from (select c.customer_code, i.id_number, cc.MemberInternalKey,
min(MemberInternalKey) over (partition by customer_code) as minmik,
max(MemberInternalKey) over (partition by customer_code) as maxmik
from Vendor1.dbo.customer_info c join
Vendor1.dbo.customer_ids i
on c.customer_code = i.customer_code join
Vendor2.dbo.Clubcard as cc
on (i.id_number collate Latin1_General_CI_AS_KS) = cc.ClubCardId
where i.id_code = 'PS'
) c
where minmik <> maxmik;
This calculates the minimum and maximum MemberInternalKey for each customer_code. The outer where then returns only rows where these are different.
Another option is
Declare #YourTable table (customer_code int, id_number int, MemberInternalKey int)
Insert Into #YourTable values
(5549032,4000,4926877),
(5549032,4001,4926877),
(5031101,4007,2379218),
(2831779,4029,1763760),
(2831779,4062,4950922)
Select A.*
From #YourTable A
Join (
Select customer_code
From #YourTable
Group By customer_code
Having min(MemberInternalKey)<>max(MemberInternalKey)
) B on A.customer_code=B.customer_code
Returns
customer_code id_number MemberInternalKey
2831779 4029 1763760
2831779 4062 4950922

Query in SQL Server with multiple join tables

I have 3 tables:
Table Position:
KodePosition | NamePosition | UserLogin
========================================
0037 Master A winz\alfa
0038 Master B winz\beta
0043 Master C winz\carlie
Table UserBackup (PJS):
KodePosition | UserOrigin | UserChange | StartDate | EndDate
================================================================
0037 winz\alfa winz\carlie 10-10-2014 17-10-2014
Table History:
IdHistory | KodePosition | StartDate | EndDate | User | Comment
===============================================================================
19F5FCFC 0038 14-10-2014 14-10-2014 winz\beta i not agree...
19F5FCFC 0043 15-10-2014 15-10-2014 winz\carlie i agree...
I want to display data like this :
Name | Date | Position | Comment
===================================================
winz\beta 14-10-2014 Master B i not agree...
winz\carlie 15-10-2014 Master A i agree...
Description :
please note the data in Table UserBackup(PJS).
if StartDate in Table History between StartDate and EndDate in Table UserBackup(PJS) and also the same UserChange with user, and then get NamePosition from Table Position by KodePosition of Table UserBackup(PJS).
For now, I have a stored procedure like this, but doesn't display the data I need.
select
A.IdHistory, A.StartDate, B.NamePosition, B.UserLogin, A.Comment
from
History as A
left join
Position as B on A.KodePosition = B.KodePosition
Where
A.IdHistory = '19F5FCFC'
order by
A.StartDate asc
Please help me guys... Thanks...
If you want to ask three tables, you can do it like this (sorry for not using your data, but I dont understand the connections of them(or your explanations)).
SELECT a.Column1, a.Column2, b.Column1
FROM table1 AS a
LEFT JOIN table2 AS b
ON a.Column1=b.Column1
WHERE (
SELECT c.Column1
FROM table3 AS c
INNER JOIN table2 as b
ON b.Column1=c.Column1
WHERE c.Column2 LIKE 'MyTarget%');
You got to think in two SELECTs, dont try to put everything in one. Btw. most DBs dont support multi Joins.
Without more information about what you are trying to do, this is a little bit of a stab in the dark...but based on your description, I believe you are trying to first filter the rows in the UserBackup(PJS) table based on whether the corresponding History.KodePosition record falls within the StartDate and EndDate of the corresponding UserBackup(PJS) record. Then, based on the returned KodePositions, you want to retrieve the related records from the Position table. I'm not sure this is the complete picture of what you are looking for, but hopefully this gets you further along:
;WITH cteData
AS (
SELECT u.KodePosition, h.IDHistory, h.StartDate, h.Comment
FROM UserBackup(PJS) u
INNER JOIN History h ON h.User = u.UserChange AND (h.StartDate >= u.Startdate and h.StartDate <= u.EndDate)
)
SELECT c.IDHistory, c.StartDate, p.NamePostition, p.UserLogin, c.Comment
FROM Position p
INNER JOIN cteData c ON c.KodePosition = p.KodePosition

Resources