2017-08-24 61 views
1

我在Vertica DB中有两个表。第一个表格有N + 1列,第二个有N列。我想查找具有相同内容但不必按相同顺序的行,以将额外列链接到第二个表。下面是N = 3的例子:SQL:查找具有匹配内容的行(与列无关)

表1:

+-------+-------+-------+-------+ 
| Item1 | Item2 | Item3 | Value | 
+-------+-------+-------+-------+ 
| A  | B  | C  |  3 | 
| C  | D  | E  |  2 | 
+-------+-------+-------+-------+ 

表2:

+-------+-------+-------+ 
| Item1 | Item2 | Item3 | 
+-------+-------+-------+ 
| C  | F  | E  | 
| C  | A  | B  | 
+-------+-------+-------+ 

正如可以看到,在排含量计从表1中的第一行是等于Table2中的第二行(期望值列)以不同的顺序排列。所以我的问题是:有没有办法链接两个表,以便将Value复制到Table中。获得最终表格。

TableF:

+-------+-------+-------+-------+ 
| Item1 | Item2 | Item3 | Value | 
+-------+-------+-------+-------+ 
| C  | A  | B  |  3 | 
+-------+-------+-------+-------+ 

可能的解决方案将是同时订购表字母数字(Table1_sorted,Table2_sorted)所示:

SELECT T2.Item1, T2.Item2, T2.Item3, T1.Value 
FROM Table1_sorted T1, Table2_sorted T2 
WHERE T1.Item1=T2.Item1 AND T1.Item2 = T2.Item2 AND T1.Item3 = T2.Item3 

然而排序字母是相当复杂的。另一种方法是使用一堆ANDOR组合,这也是不理想的。我想知道是否有更简单的解决方案。

谢谢!

+0

固定列数?或者N可以大于3所示的例子? –

+0

理想情况下,N会大于3 – valenzio

回答

2

您可以创建一个UDx Scalar Function,它将检查行级别上的相等性。您可以对元组进行排序或从元组中创建集合。我将在Python上展示一个例子,但强烈建议在JAVA或C++上编写UDF。 (上youtube充分演示)

dbadmin=> select * from t1; 
item1 | item2 | item3 | value 
-------+-------+-------+------- 
A  | B  | C  |  3 
C  | D  | E  |  2 
(2 rows) 

dbadmin=> select * from t2; 
item1 | item2 | item3 
-------+-------+------- 
C  | A  | B 
C  | F  | E 
(2 rows) 

dbadmin=> select t1.* from t1, t2 where perm(t1.item1, t1.item2, t1.item3, t2.*); 
item1 | item2 | item3 | value 
-------+-------+-------+------- 
A  | B  | C  |  3 
(1 row) 

如果元组的次序是重要的:

dbadmin=> select t2.*, t1.value from t1, t2 
dbadmin-> where perm(t1.item1, t1.item2, t1.item3, t2.*); 
item1 | item2 | item3 | value 
-------+-------+-------+------- 
C  | A  | B  |  3 
(1 row) 

例如有关python(对于Vertica的8.x中)

1版本:

def processBlock(self, server_interface, arg_reader, res_writer): 
    while(True): 
     cols = arg_reader.getNumCols() 
     if cols % 2 != 0: 
      raise ValueError("num of columns must be even") 
     s1, s2 = set(), set() 
     for i in range(cols): 
      if i < cols/2: 
       s1.add(arg_reader.getString(i)) 
      else: 
       s2.add(arg_reader.getString(i)) 
     res_writer.setBool(s1 == s2) 
     res_writer.next() 
     if not arg_reader.next(): 
      break 

版本2 :

def processBlock(self, server_interface, arg_reader, res_writer): 
    while(True): 
     cols = arg_reader.getNumCols() 
     if cols % 2 != 0: 
      raise ValueError("num of cols must be even") 
     s = set() 
     for i in range(cols): 
      s.add(arg_reader.getString(i)) 
     res_writer.setBool(len(s) == cols/2) 
     res_writer.next() 
     if not arg_reader.next(): 
      break 

全码:

import vertica_sdk 

class perm(vertica_sdk.ScalarFunction): 

    def __init__(self): 
     pass 

    def setup(self, server_interface, col_types): 
     pass 

    def processBlock(self, server_interface, arg_reader, res_writer): 
     #server_interface.log("log msg") 
     while(True): 
      # Example of error checking best practices. 
      cols = arg_reader.getNumCols() 
      if cols % 2 != 0: 
       raise ValueError("num of cols must be even") 
      s = set() 
      for i in range(cols): 
       s.add(arg_reader.getString(i)) 
      res_writer.setBool(len(s) == cols/2) 
      res_writer.next() 
      if not arg_reader.next(): 
       break 

    def destroy(self, server_interface, col_types): 
     pass 

class perm_factory(vertica_sdk.ScalarFunctionFactory): 

    def createScalarFunction(self, srv): 
     return perm() 

    def getPrototype(self, srv_interface, arg_types, return_type): 
     arg_types.addAny() 
     return_type.addBool() 

    def getReturnType(self, srv_interface, arg_types, return_type): 
     return_type.addBool() 
0

这里是Java版本

+package com.iav.udsf.misc; 
+ 
+import com.vertica.sdk.*; 
+import java.io.PrintWriter; 
+import java.io.StringWriter; 
+import java.util.HashSet; 
+import java.util.Set; 
+ 
+/** 
+ * 
+ * @author gdpassar 
+ */ 
+public class RowCompareFactory extends ScalarFunctionFactory { 
+ 
+ // Access to Vertica services (logging) 
+ protected ServerInterface si; 
+ 
+ /** 
+  * Method called by Vertica in order to obtain the UDF interface (input and output parameters). 
+  * Default is to have two input parameteres (a String representing the time intervals and a binary 
+  * object containing the signal to analyse) and a String output parameter (representing a time 
+  * interval, can be NULL if the UDF did not successfully apply to the given signal) 
+  * @param srvInterface Vertica server interface 
+  * @param argTypes Object for adding input parameters 
+  * @param returnType Object for adding output parameters 
+  */ 
+ @Override 
+ public void getPrototype(ServerInterface srvInterface, 
+        ColumnTypes argTypes, 
+        ColumnTypes returnType) 
+ { 
+  argTypes.addAny(); 
+ 
+  returnType.addBool(); 
+ } 
+ 
+ /** 
+  * Method called by Vertica in order to obtain the return value type. 
+  * @param srvInterface Vertica server interface 
+  * @param argTypes Not used 
+  * @param returnType Not used 
+  */ 
+ @Override 
+ public void getReturnType(ServerInterface srvInterface, SizedColumnTypes argTypes, SizedColumnTypes returnType) { 
+  returnType.addBool(); 
+ } 
+ 
+ /** 
+  * UDF standard class, containing the parsing logic of the input parameters 
+  */ 
+ public class udf extends ScalarFunction { 
+ 
+  @Override 
+  public void processBlock(ServerInterface srvInterface, 
+         BlockReader argReader, 
+         BlockWriter resWriter) 
+     throws UdfException, DestroyInvocation { 
+   si = srvInterface; 
+ 
+   do { 
+    Set<Object> itemSet = new HashSet<>(); 
+    final int numCols = argReader.getNumCols(); 
+    if ((numCols % 2) != 0) { 
+     throw new UdfException(0, "Number of columns must be even"); 
+    } 
+    try { 
+     itemSet.clear(); 
+     for (int i = 0; i < numCols; i++) { 
+      if (argReader.getTypeMetaData().getColumnType(i).isVarchar()) { 
+       itemSet.add(argReader.getString(i)); 
+      } else if (argReader.getTypeMetaData().getColumnType(i).isInt()) { 
+       itemSet.add(argReader.getLong(i)); 
+      } else if (argReader.getTypeMetaData().getColumnType(i).isDate()) { 
+       itemSet.add(argReader.getDate(i)); 
+      } else if (argReader.getTypeMetaData().getColumnType(i).isFloat()) { 
+       itemSet.add(argReader.getDouble(i)); 
+      } else if (argReader.getTypeMetaData().getColumnType(i).isTimestamp()) { 
+       itemSet.add(argReader.getTimestamp(i)); 
+      } else if (argReader.getTypeMetaData().getColumnType(i).isBool()) { 
+       itemSet.add(argReader.getBoolean(i)); 
+      } else { 
+       throw new UdfException(0, "Data type not supported"); 
+      } 
+     } 
+      
+     resWriter.setBoolean(itemSet.size() == (numCols/2)); 
+ 
+    } catch (Exception ex) { 
+     StringWriter sw = new StringWriter(); 
+     PrintWriter pw = new PrintWriter(sw); 
+     ex.printStackTrace(pw); 
+     si.log(sw.toString()); 
+     resWriter.setBoolean(false); 
+    } 
+    resWriter.next(); 
+   } while (argReader.next()); 
+  } 
+ } 
+ 
+ /** 
+  * Method called by Vertica in order to instantiate a new UDF when the query runs. 
+  * @param srvInterface Vertica server interface 
+  * @return Instance of a scalar function 
+  */ 
+ @Override 
+ public ScalarFunction createScalarFunction(ServerInterface srvInterface) 
+ { 
+  return new udf(); 
+ } 
+} 
+0

不错,它比'python'好得多。正如我在实施之前所说的那样,只是一个概念/例子。它适合你吗? – sKwa

+0

是的,它的工作非常好,谢谢你的想法! – valenzio

相关问题