查询两个表并根据第一个匹配填充一列

时间:2015-04-27 14:22:45

标签: sql-server join header match

这是我确定已经讨论了1000次的事情之一,但我所有的搜索都没有达到理解我的需要。

两个表:分类帐和患者

我想从分类帐中选择多个列,并根据两个匹配的记录从患者添加一列。这是我写的查询,但它只是永远运行:

SELECT 
   ledger.OID
    , ledger.PATID
    , ledger.PROVIDERID
    , ledger.LTYPE
    , ledger.TRANDATE
    , ledger.ESTINS
    , ledger.AMOUNT
    , ledger.PATPAID
    , ledger.PATADJUST
    , ledger.LEDGERID
    , ledger.TYPE2
    , ledger.rpid
    , patient.oid
    , ledger.DESCR
FROM 
    [exportb].[dbo].[LEDGER]
    , exportb.dbo.patient
INNER JOIN 
    LEDGER AS LEDGE ON LEDGE.rpid = PATIENT.rpid
WHERE 
    ledger.PATID > '0'
    AND ledger.LTYPE <> 'M'
    AND ledger.LTYPE <> 'n'
    AND (
        ledger.ESTINS <> '0'
        OR ledger.AMOUNT <> '0'
        OR ledger.PATPAID <> '0'
        OR ledger.PATADJUST <> '0'
        )

当我在没有patient.oid和join语句的情况下运行它时,我得到了40037条记录,这正是我想要的。

我想要做的是将patient.oid标题添加到我的结果中。我希望查询查看LEDGER.RPID列并与PATIENT.RPID列匹配,并为该记录填充PATIENT.OID

我确信这很简单,但希望有人可以解决一些问题!

2 个答案:

答案 0 :(得分:0)

您没有加入dbo.patient的谓词,因此正在进行交叉加入(Cartesian Product):

from [exportb].[dbo].[LEDGER],exportb.dbo.patient

这应该是:

FROM    dbo.Ledger
        INNER JOIN dbo.Patient
            ON Patient.rpid = Ledger.rpid

除了连接之外,你也永远不会将别名为LEDGE的表格引用,所以你也可以完全删除它。所以,我认为你所追求的是:

USE Exportb;

SELECT  l.OID,
        l.PATID,
        l.PROVIDERID,
        l.LTYPE,
        l.TRANDATE,
        l.ESTINS,
        l.AMOUNT,
        l.PATPAID,
        l.PATADJUST, 
        l.LEDGERID, 
        l.TYPE2, 
        l.rpid, 
        p.oid, 
        l.DESCR 
FROM    dbo.Ledger AS l
        INNER JOIN dbo.Patient AS p
            ON p.rpid = l.rpid
WHERE   l.PATID > 0
AND     l.LType NOT IN ('M', 'n')
AND     (l.Estins <> 0 OR l.Amount <> 0 OR l.PatAdjust <> 0);

值得注意的是,我已删除了交叉联接,并将单个联接保留为dbo.Patient。我简化了以下谓词:

AND ledger.LTYPE <> 'M' 
AND ledger.LTYPE <> 'n' 

AND     l.LType NOT IN ('M', 'n')

我还假设单引号中的数字常量以避免隐式转换,并从以下行中删除了ledger.PATPAID <>'0'

AND (ledger.ESTINS <> '0' OR ledger.AMOUNT <> '0' or ledger.PATPAID <>'0' or ledger.PATADJUST <> '0')

由于谓词,部分永远不可能是真的:

WHERE   l.PATID > 0

如果您有从分类帐到患者的一对多关系,即您在dbo.patient中有多行并且只关心第一场比赛,那么您需要将联接更改为APPLY并使用TOP 1获取单行。你的标题似乎暗示你想要“第一场比赛”,但问题并没有解释你如何定义“第一场”:

USE Exportb;

SELECT  l.OID,
        l.PATID,
        l.PROVIDERID,
        l.LTYPE,
        l.TRANDATE,
        l.ESTINS,
        l.AMOUNT,
        l.PATPAID,
        l.PATADJUST, 
        l.LEDGERID, 
        l.TYPE2, 
        l.rpid, 
        p.oid, 
        l.DESCR 
FROM    dbo.Ledger AS l
        CROSS APPLY
        (   SELECT  TOP 1 p.oid
            FROM    dbo.Patient AS p
            WHERE   p.rpid = l.rpid
            ORDER BY p.oid -- YOU MAY NEED TO CHANGE THIS ORDER DEPENDING ON YOUR CRITERIA
        ) AS p
WHERE   l.PATID > 0
AND     l.LType NOT IN ('M', 'n')
AND     (l.Estins <> 0 OR l.Amount <> 0 OR l.PatAdjust <> 0);

答案 1 :(得分:0)

您正在寻找LEFT JOIN我的朋友。将联接从INNER更改为LEFT,您将获得结果。

Patient.OID将是NULL,其中没有匹配项。

是的,from子句和join子句不正确,这就是它永远运行的原因。

将其更改为:

from [exportb].[dbo].[LEDGER] LEDGE
LEFT JOIN exportb.dbo.patient ON LEDGE.rpid = PATIENT.rpid