如何识别两行不同的单元格?

时间:2018-01-30 13:18:03

标签: sql sql-server r tsql

有时我想知道是否有一个很好的做法来确定数据库表的两行在它们应该是eqal时不同的单元格。这是一个非常简单的问题场景:

两张桌子各有一行:

select 1 c1, 2 c2, 3 c3 into #t1
select 1 c1, 2 c2, 4 c3 into #t2

这两行被标识为不同(我不知道如何识别这些行。在这个szenario中,由union-operator识别出的重复。我可以使用二进制校验和或其他。这不是问题。)

select * from #t1
union
select * from #t2

在这种情况下,很明显(非常简单和快速)看到c3(值3和4)使得两行之间的差异应该是相等的。

1   2   3
1   2   4

当存在列数时,如何识别不匹配的单元格? (不要告诉我不要创建这样的表......)

有通用方法吗?我更喜欢某种突出的'不同的细胞。 (也许使用R-in-database并导出到excel?...)

解决问题的另一种方法:

我有一个表,其中id应该是唯一标识符 - 但事实并非如此。我必须分析表中的数据。

 if object_id('tempdb..#t1') is not null drop table #t1

 create table #t1 (
 id int,
 c01 int,
 c02 int,
 c03 int,
 c04 int,
 c05 int,
 c06 int,
 c07 int,
 c08 int,
 c09 int,
 c10 int,
 c11 int,
 c12 int,
 c13 int,
 c14 int,
 c15 int,
 c16 int,
 c17 int,
 c18 int,
 c19 int,
 c20 int,
 c21 int,
 c22 int,
 c23 int,
 c24 int,
 c25 int,
 c26 int,
 c27 int,
 c28 int,
 c29 int,
 c30 int,
 c31 int,
 c32 int,
 c33 int,
 c34 int,
 c35 int,
 c36 int,
 c37 int,
 c38 int,
 c39 int,
 c40 int,
 c41 int,
 c42 int,
 c43 int,
 c44 int,
 c45 int,
 c46 int,
 c47 int,
 c48 int,
 c49 int
 )

 insert #t1 (id, c11) values (1, 1)
 insert #t1 (id, c12) values (1, 1)

 insert #t1 (id, c11) values (2, 1)
 insert #t1 (id, c11) values (3, 1)

 insert #t1 (id, c21) values (4, 1)
 insert #t1 (id, c32) values (4, 1)

这就是我所做的:我查看数据"有问题",即某些单元格中具有不同值的数据。当列很少时,此任务很简单。如果有列的内容(并且几乎没有像本例中的所有内容都是NULL),这是一项艰巨的任务。

 select a.* from #t1 a
 inner join (select id from #t1 group by id having count(*) > 1) b
 on a.id = b.id
 order by id

我想看到不同的细胞名称。在这个例子中,例如像这样的结果集。

 id columnname
 1  c11
 1  c12
 4  c21
 4  c32

SSMS中的黄色细胞也会很好......

2 个答案:

答案 0 :(得分:2)

以下将"动态"使用一点XML来取消您的数据。

UnPivot会更高效,但至少在这里你不必指定所有字段

示例

annotate

<强>返回

library(ggplot2)
library(grid)
library(extrafont)
g <- ggplot(data = df, aes(x = 1, y = value, fill = factor(group))) +
  geom_bar(position = "stack", stat = "identity") + 
  theme(plot.margin = unit(c(.5, 0.2, 0, 0.1), "in")
        , axis.line = element_blank()  
        , axis.text.x = element_blank()  
        , axis.text.y = element_blank()  
        , axis.ticks = element_blank() 
        , axis.title.x = element_blank() 
        , axis.title.y = element_blank()  
        , panel.background = element_blank()  
        , panel.border = element_blank()  
        , panel.grid.major = element_blank()  
        , panel.grid.minor = element_blank()  
        , plot.background = element_blank()  
        , legend.position=""          
        ) +
  scale_fill_manual(values=c("#595959", "#E26B0A", "#00B0F0"), 
                    breaks=c("Group 1","Group 2","Group 3"),
                    labels=lables) +
  coord_flip() +
  annotate("text", label=lables[1], x=1.8, y = df$value[1]/2           
                , fontface = "bold", color = "#595959", family="Arial", size = 4.5) +  
  annotate("text", label=lables[2], x=1.8, y = sum(df$value)-400000           
           , fontface = "bold", color = "#E26B0A", family="Arial", size = 4.5) +  
  annotate("text", label=lables[3], x=1.8, y = sum(df$value)-100000           
           , fontface = "bold", color = "#00B0F0", family="Arial", size = 4.5) 

g
  

修改

用于查找具有不同值的行的快捷方式

;with cte as (
Select A.ID
      ,C.*
      ,Fields = sum(1) over (Partition by A.ID)
      ,Vals   = sum(1) over (Partition by A.ID,Field,Value)
 From #t1 A
 Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
 Cross Apply (
                Select Field = a.value('local-name(.)','varchar(100)')
                      ,Value = a.value('.','varchar(max)') 
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') not in ('id','OtherExcludeColumns')
             ) C
) 
Select ID
      ,Field
 From  cte
 Where Fields>1 and Vals=1 

返回

ID  Field
1   c11
1   c12
4   c21
4   c32

答案 1 :(得分:0)

使用UNPIVOT将表格转换为每列一行,并比较匹配的列:

 SELECT tu1.cell_name, tu1.cell_value, tu2.cell_value
 FROM (SELECT cell_name, cell_value
       FROM #t1
       UNPIVOT (cell_value FOR cell_name IN c1, c2, c3)) tu1
 JOIN (SELECT cell_name, cell_value
       FROM #t2
       UNPIVOT (cell_value FOR cell_name IN c1, c2, c3)) tu2
 ON (tu1.cell_name = tu2.cell_name AND tu1.cell_value <> tu2.cell_value);

未经测试,SQL Fiddle正在采取行动。

如果您事先不知道列,请参阅https://stackoverflow.com/a/13377114/108326了解如何动态调用UNPIVOT。此方法从数据库元数据中检索列列表,然后即时生成UNPIVOT查询。