Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何在列发生更改时选择列?_Sql_Postgresql_Netezza - Fatal编程技术网

Sql 如何在列发生更改时选择列?

Sql 如何在列发生更改时选择列?,sql,postgresql,netezza,Sql,Postgresql,Netezza,我试图创建一个缓慢变化的维度(类型2维度),但我对如何逻辑地写出它有点迷茫。假设我们有一个源表,其中包含Person | Country | Department | Login Time。我想用Person | Country | Department | Eff Start time | Eff End time创建此维度表 数据可能如下所示: Person | Country | Department | Login Time -------------------------------

我试图创建一个缓慢变化的维度(类型2维度),但我对如何逻辑地写出它有点迷茫。假设我们有一个源表,其中包含
Person | Country | Department | Login Time
。我想用
Person | Country | Department | Eff Start time | Eff End time
创建此维度表

数据可能如下所示:

Person | Country | Department | Login Time
------------------------------------------
Bob    | CANADA  | Marketing  | 2009-01-01
Bob    | CANADA  | Marketing  | 2009-02-01
Bob    | USA     | Marketing  | 2009-03-01
Bob    | USA     | Sales      | 2009-04-01
Bob    | MEX     | Product    | 2009-05-01
Bob    | MEX     | Product    | 2009-06-01
Bob    | MEX     | Product    | 2009-07-01
Bob    | CANADA  | Marketing  | 2009-08-01
我想要的类型2维度如下所示:

Person | Country | Department | Eff Start time | Eff End Time
------------------------------------------------------------------
Bob    | CANADA  | Marketing  | 2009-01-01     | 2009-03-01
Bob    | USA     | Marketing  | 2009-03-01     | 2009-04-01
Bob    | USA     | Sales      | 2009-04-01     | 2009-05-01
Bob    | MEX     | Product    | 2009-05-01     | 2009-08-01
Bob    | CANADA  | Marketing  | 2009-08-01     | NULL 
假设Bob的姓名、国家/地区和部门自2009-08-01以来没有更新过,因此保留为
NULL

什么功能在这里最有效?这是在Netezza上,它使用Postgres的风格

显然,
groupby
在这里不起作用,因为后面会有相同的分组(我在最后一行添加了
Bob | CANADA | Marketing
,以显示这一点)

编辑

包括一个关于个人、国家和部门的哈希列,将有意义,正确地考虑使用

SELECT PERSON, COUNTRY, DEPARTMENT
FROM table t1
where 
    person = person 
    AND t1.hash <> hash_function(person, country, department)
选择人员、国家/地区、部门
来自表t1
哪里
人
和t1.hash散列函数(个人、国家、部门)
答案 此代码返回下表

 PERSON | COUNTRY | DEPARTMENT | EFF_LOGIN_START | EFF_LOGIN_END
--------+---------+------------+-----------------+---------------
 Bob    | CANADA  | Marketing  | 2009-01-01      | 2009-03-01
 Bob    | USA     | Marketing  | 2009-03-01      | 2009-04-01
 Bob    | USA     | Sales      | 2009-04-01      | 2009-05-01
 Bob    | MEX     | Product    | 2009-05-01      | 2009-08-01
 Bob    | CANADA  | Marketing  | 2009-08-01      |
解释 在过去的几年里,我一定已经解决了四五次这个问题,但一直没有把它正式写下来。我很高兴有机会这样做,所以这是一个很好的问题

在尝试这一点时,我喜欢用矩阵形式写下问题。这里是输入,假设所有值在SCD中都有相同的键

 Cv | Ce
----|----
 A  | 10
 A  | 11
 B  | 14
 C  | 16
 D  | 18
 D  | 25
 D  | 34
 A  | 40
其中Cv是我们需要比较的值(同样,假设SCD的键值在此数据中相等;我们将在整个时间内对键值进行分区,因此它与解决方案无关),Ce是事件时间

首先,我们需要一个顺序主键。我在表中指定了这个Ck。这将允许我们将表连接到它自己,以获得上一个和下一个事件。我将这些列称为Pk(上一个键)、Nk(下一个键)、Pv和Nv

 Cv | Ce | Ck | Pk | Pv | Nk | Nv |
----|----|----|----|----|----|----|
 A  | 10 | 1  |    |    | 2  | A  |
 A  | 11 | 2  | 1  | A  | 3  | B  |
 B  | 14 | 3  | 2  | A  | 4  | C  |
 C  | 16 | 4  | 3  | B  | 5  | D  |
 D  | 18 | 5  | 4  | C  | 6  | D  |
 D  | 25 | 6  | 5  | D  | 7  | D  |
 D  | 34 | 7  | 6  | D  | 8  | A  |
 A  | 40 | 8  | 7  | D  |    |    |
现在我们需要一些列来查看我们是否在连续事件块的开头或结尾。我将调用这些Pc和Nc,因为它们是连续的。Pc被定义为Pv=Cv=>true。1表示true,0表示false。Nc的定义与此类似,只是null大小写默认为true(我们将在一分钟后了解原因)

现在你可以开始看到Pc,Nc的1,1组合是一个完全无用的记录。我们直观地知道这一点,因为Bob在第6排的Mex/产品组合在构建SCD时几乎是无用的信息

所以,让我们去掉无用的信息。我将在这里添加两个新列:几乎完整的有效开始时间(称为Sn)和实际完整的有效结束时间(称为Ee)。当Pc为0时,Sn用Ce填充,当Nc为0时,Ee用Ce填充

 Cv | Ce | Ck | Pk | Pv | Nk | Nv | Pc | Nc | Sn | Ee |
----|----|----|----|----|----|----|----|----|----|----|
 A  | 10 | 1  |    |    | 2  | A  | 0  | 1  | 10 |    |
 A  | 11 | 2  | 1  | A  | 3  | B  | 1  | 0  |    | 11 |
 B  | 14 | 3  | 2  | A  | 4  | C  | 0  | 0  | 14 | 14 |
 C  | 16 | 4  | 3  | B  | 5  | D  | 0  | 0  | 16 | 16 |
 D  | 18 | 5  | 4  | C  | 6  | D  | 0  | 1  | 18 |    |
 D  | 25 | 6  | 5  | D  | 7  | D  | 1  | 1  |    |    |
 D  | 34 | 7  | 6  | D  | 8  | A  | 1  | 0  |    | 34 |
 A  | 40 | 8  | 7  | D  |    |    | 0  | 1  | 40 |    |
这看起来非常接近,但我们仍然存在无法按简历(个人/国家/部门)分组的问题。我们需要的是Sn用Sn的前一个值填充所有这些空值。您可以在
rwn
上将此表连接到自身并获得最大值,但我会很懒,使用Netezza的分析函数和
rows unbounded previous
子句。这是我刚才描述的方法的快捷方式。因此,我们将创建另一个名为Es的列,effectivestart,定义如下

case
  when Sn is null
    then max(Sn) over (
      partition by k --key value of the SCD
      order by Ck
      rows unbounded preceding
    )
  else Sn
end Es
根据这个定义,我们得到了这个

 Cv | Ce | Ck | Pk | Pv | Nk | Nv | Pc | Nc | Sn | Ee | Es |
----|----|----|----|----|----|----|----|----|----|----|----|
 A  | 10 | 1  |    |    | 2  | A  | 0  | 1  | 10 |    | 10 |
 A  | 11 | 2  | 1  | A  | 3  | B  | 1  | 0  |    | 11 | 10 |
 B  | 14 | 3  | 2  | A  | 4  | C  | 0  | 0  | 14 | 14 | 14 |
 C  | 16 | 4  | 3  | B  | 5  | D  | 0  | 0  | 16 | 16 | 16 |
 D  | 18 | 5  | 4  | C  | 6  | D  | 0  | 1  | 18 |    | 18 |
 D  | 25 | 6  | 5  | D  | 7  | D  | 1  | 1  |    |    | 18 |
 D  | 34 | 7  | 6  | D  | 8  | A  | 1  | 0  |    | 34 | 18 |
 A  | 40 | 8  | 7  | D  |    |    | 0  | 1  | 40 |    | 40 |
其余的都很简单。按Es分组并获取Ee的最大值以获得此表

 Cv | Es | Ee |
----|----|----|
 A  | 10 | 11 |
 B  | 14 | 14 |
 C  | 16 | 16 |
 D  | 18 | 34 |
 A  | 40 |    |

如果要用下一个开始填充有效结束时间,请将表再次连接到表本身或使用
lead()
窗口函数来获取它。

你能详细说明你的要求吗?当你说“选择列”时,你到底想做什么?举一个你想要的例子会很有帮助。是的,我可以用一个更好的标题。基本上,在我给出的例子中,我想找到一个人、他们的国家和t他们的部门在历史上的某个时刻或目前的某个时刻。为了做到这一点,由于这个维度可能会发生变化,我想找到,当这些列为您指定的编辑而发生变化时,您是否应该得到您期望的输出?与以前相同的输出?您希望代码生成维度?还是加入维度?另外,您的
hash_函数
建议可以在Netezza上使用,但您也可以很容易地不使用预先计算的区域映射。只要让Netezza按照优化器想要做的任何事情进行比较即可。
 Cv | Ce | Ck | Pk | Pv | Nk | Nv | Pc | Nc | Sn | Ee | Es |
----|----|----|----|----|----|----|----|----|----|----|----|
 A  | 10 | 1  |    |    | 2  | A  | 0  | 1  | 10 |    | 10 |
 A  | 11 | 2  | 1  | A  | 3  | B  | 1  | 0  |    | 11 | 10 |
 B  | 14 | 3  | 2  | A  | 4  | C  | 0  | 0  | 14 | 14 | 14 |
 C  | 16 | 4  | 3  | B  | 5  | D  | 0  | 0  | 16 | 16 | 16 |
 D  | 18 | 5  | 4  | C  | 6  | D  | 0  | 1  | 18 |    | 18 |
 D  | 25 | 6  | 5  | D  | 7  | D  | 1  | 1  |    |    | 18 |
 D  | 34 | 7  | 6  | D  | 8  | A  | 1  | 0  |    | 34 | 18 |
 A  | 40 | 8  | 7  | D  |    |    | 0  | 1  | 40 |    | 40 |
 Cv | Es | Ee |
----|----|----|
 A  | 10 | 11 |
 B  | 14 | 14 |
 C  | 16 | 16 |
 D  | 18 | 34 |
 A  | 40 |    |