【问题标题】:Is it possible that left side in a left outer join to repeat only once左外连接中的左侧是否可能只重复一次
【发布时间】:2015-06-13 11:47:13
【问题描述】:

我有一个场景。不确定是否可以通过简单的sql查询。

表 1

create table table1 (rowno int,
                     fileid int,
                     filename varchar(50),
                     filedata varchar(50),
                     valid boolean
                     );

insert into table1 (RowNo , FileId , FileName , fileData , Valid) values
(1, 1, 'FileA', 'blah blah..', true),
(2, 1, 'FileA', 'blah blah..', true),
(3, 1, 'FileA', 'blah blah..', true),
(4, 1, 'FileA', 'blah blah..', true),
(1, 2, 'FileB', 'blah blah..', false),
(2, 2, 'FileB', 'blah blah..', true),
(3, 2, 'FileB', 'blah blah..', false);

上面会给出一个表格如下,-

RowNo | FileId | FileName | Data        | Valid
1     |1       | FileA    | blah blah.. | TRUE 
2     |1       | FileA    | blah blah.. | TRUE 
3     |1       | FileA    | blah blah.. | TRUE 
4     |1       | FileA    | blah blah.. | TRUE 
1     |2       | FileB    | blah blah.. | FALSE 
2     |2       | FileB    | blah blah.. | TRUE 
3     |2       | FileB    | blah blah.. | FALSE 

表2

create table table2 (fileid int,
                     rowno int,
                     errormsg varchar(100)
                    );
insert into table2 (fileid , rowno , errormsg ) values (2,1,'manatory field is blank');
insert into table2 (fileid , rowno , errormsg ) values (2,3,'date format is wrong');

上面会给出一个表格如下,-

FILEID  |ROWNO   |ERRORMSG   
2       |1       |manatory field is blank 
2       |3       |date format is wrong 

如果我用下面的查询加入上表,-

select distinct t1.FILENAME,tot.TOTALREC, VALIDREC,coalesce((tot.TOTALREC- VALIDREC),0)INVALIDREC, t2.Rowno , case when coalesce((tot.TOTALREC- VALIDREC),0)=0 then null else t1.filedata end as ErrorData , t2.errormsg as ErrorMessage
from table1 t1
join (select count(*) totalrec, fileid from table1 group by fileid)tot on t1.fileid=tot.fileid
join (select count(*) VALIDREC , fileid from table1 where valid=true group by fileid)valid on t1.fileid=valid.fileid
left outer join table2 t2 on t1.fileid=t2.fileid 
order by t1.FILENAME;

我得到以下结果,-

实际结果

FILENAME | TOTALREC | VALIDREC | INVALIDREC | ROWNO | ERRORDATA | ERRORMESSAGE   
FileA    |   4      |    4     |     0      | null  | null      | null 
FileB    |   3      |    1     |     2      | 1     |blah blah..| manatory field is blank 
FileB    |   3      |    1     |     2      | 3     |blah blah..| date format is wrong 

但我需要一个如下的结果集。

预期结果

FILENAME |TOTALREC|VALIDREC|INVALIDREC|ROWNO| ERRORDATA | ERRORMESSAGE   
FileA    |   4    |    4   |    0     | null| null      | null 
FileB    |   3    |    1   |    2     | 1   |blah blah..| manatory field is blank 
         |        |        |          | 3   |blah blah..| date format is wrong 

(注意最后一行的前四列。)

如果可以的话,谁能帮我查询一下?

更新: 按照你们中的许多人的要求澄清我的要求。

【问题讨论】:

  • 我确信无论您尝试做什么都是可能的。但是,正如发布的那样,您要做什么非常不清楚。
  • 你能简单解释一下为什么预期的结果只是这样吗?
  • 在 SQL Server 中是可能的。不了解 MySQL。
  • 您在寻找哪个:MySQL 还是 SQL Server?
  • @halfer--> 数据库可以是任何东西。就我而言,它是 H2 数据库。

标签: mysql sql-server optimization h2 outer-join


【解决方案1】:

首先感谢大家的帮助。

@Rick --> 这是可能的。

一段时间以来,我一直在寻找专门针对 H2 数据库的解决方案。但是,尽管如此,该解决方案应该适用于大多数支持 ranking 或任何实现该功能的数据库。我在Stackoverflow link 中找到了排名方法。

之后就是小菜一碟了!!

这里是解决方案查询,有兴趣的-

select 
case when (final.INVALIDREC>0 and final.ranking>1) then '' else final.FileName end as FileName,
case when (final.INVALIDREC>0 and final.ranking>1) then '' else cast(final.TOTALREC as varchar(50)) end as TOTALREC,
case when (final.INVALIDREC>0 and final.ranking>1) then '' else cast(final.VALIDREC as varchar(50)) end as VALIDREC,
case when (final.INVALIDREC>0 and final.ranking>1) then '' else cast(final.INVALIDREC as varchar(50)) end as INVALIDREC, final.Rowno , final.ErrorData , final.ErrorMessage
from
(select 
   (
    select  count(*)
    from    (select distinct t1.FILENAME, t2.Rowno from table1 t1
    left outer join table2 t2 on t1.fileid=t2.fileid 
    order by t1.FILENAME) yt2
    where   yt2.FILENAME = temp.FILENAME -- Same partition
            and yt2.Rowno <= temp.Rowno -- Lower or equal rank
    ) as ranking,
temp.FILENAME,temp.TOTALREC, temp.VALIDREC,temp.INVALIDREC, temp.Rowno , temp.ErrorData , temp.ErrorMessage
from
(select distinct t1.FILENAME,tot.TOTALREC, VALIDREC,coalesce((tot.TOTALREC- VALIDREC),0)INVALIDREC, t2.Rowno , case when coalesce((tot.TOTALREC- VALIDREC),0)=0 then null else t1.filedata end as ErrorData , t2.errormsg as ErrorMessage
from table1 t1
join (select count(*) totalrec, fileid from table1 group by fileid)tot on t1.fileid=tot.fileid
join (select count(*) VALIDREC , fileid from table1 where valid=true group by fileid)valid on t1.fileid=valid.fileid
left outer join table2 t2 on t1.fileid=t2.fileid 
order by t1.FILENAME, t2.rowno) temp)final;

这将给出预期结果

*谢谢大家..这是我在 Stack Overflow 上的第一篇文章,在获得这么多帮助时我感到很谦虚..

编码愉快!!*

【讨论】:

    【解决方案2】:

    看不到您在那里使用的 SQL,但作为一般规则,如果您有类似的东西:

    CASE WHEN RANK() OVER (PARTITIION BY a.filename ORDER BY a.rowno DESC) = 1 THEN <insert column here> END
    

    它将根据每个文件中的第一行等过滤掉重复项。

    在 SQL Server 中,这确实提供了一种将掩码应用于某些记录而不是其他记录的方法。

    【讨论】:

    • 不清楚 OP 有哪个数据库,但 afaik MySQL 没有窗口函数。
    • @Simon--> 对。这就是我在那里所做的。我的数据库是 H2 数据库。我花了一段时间才找出 H2 中的排名。
    【解决方案3】:

    据我了解,如果某些字段与上一行中的相应字段相同,您希望将其留空吗?

    没有办法直接在 MySQL 中执行此操作。你最好用应用程序语言(PHP、VB、Java 等)来做。

    可以使用@variables、IF() 函数调用和ORDER BY 来做到这一点。

    【讨论】:

      【解决方案4】:

      COALESCE 就是你想要的。

      Select t.myfield, coalesce(t2.Myfield2, '') 
      from mytable t
      left join mytable2 t2 on t.mytableid = t2.mytableid
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-27
        • 2013-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 2018-07-11
        相关资源
        最近更新 更多