Как сохранить последнюю контрольную точку в sql, которая будет использоваться для следующей строки

Можно ли сохранить последний результат итерационной строки и использовать ее для следующей итерации строки?

Например, у меня есть таблица say (Time_Table).

__   Key   type   timeStamp             
1 )    1     B    2015-06-28 09:00:00  
2 )    1     B    2015-06-28 10:00:00  
3 )    1     C    2015-06-28 11:00:00  
4 )    1     A    2015-06-28 12:00:00  
5 )    1     B    2015-06-28 13:00:00  

Теперь предположим, что у меня есть exceptionTime 90 минут, который является постоянным. Если я начну проверять свой Time_Table, то:

  • для первой строки, так как нет строки до 09:00:00,, она будет напрямую помещать эту запись в мою целевую таблицу. Теперь моя точка отсчета находится в 9:00:00.

  • Для второй строки в 10:00:00, последняя опорная точка была 09:00:00 и TIMESTAMPDIFF(s,09:00:00,10:00:00) равна 60, что меньше требуемого 90. Я не добавляю эту строку в свою целевую таблицу.

  • Для третьей строки последнее записанное исключение было в 09:00:00, а TIMESTAMPDIFF(s,09:00:00,11:00:00) равно 120, что больше требуемых 90, поэтому я выбираю эту запись и устанавливаю опорную точку на 11:00:00.

  • Для четвертой строки TIMESTAMPDIFF(s,11:00:00,12:00:00). Точно так же он не будет сохранен.

  • Это снова сохраняется.

Таблица целей

__   Key   type   timeStamp             
1 )    1     B    2015-06-28 09:00:00  
2 )    1     C    2015-06-28 11:00:00   
3 )    1     B    2015-06-28 13:00:00 

Есть ли способ решить эту проблему purely in SQL?

Мой подход:

SELECT * FROM Time_Table A WHERE NOT EXISTS(
       SELECT 1 FROM Time_Table B
       WHERE  A.timeStamp > B.timeStamp
       AND    abs(TIMESTAMPDIFF(s,B.timeStamp,A.timeStamp)) > 90 
)

Но это не будет работать.

Ответ 1

Это невозможно с использованием только чистого SQL в Vertica. Чтобы сделать это в чистом SQL, вы должны иметь возможность выполнять рекурсивный запрос, который не поддерживается в продукте Vertica. В других продуктах базы данных вы можете сделать это, используя предложение WITH. Для Vertica вам придется делать это в логике приложения. Это основано на утверждении: "Каждое предложение WITH в блоке запроса должно иметь уникальное имя. Попытка использовать псевдонимы одинакового имени для запросов запроса предложения WITH в одном блоке запроса вызывает ошибку. WITH clauses не поддерживает INSERT, DELETE, и UPDATE, и вы не можете использовать их рекурсивно" из Документация Vertica 7.1.x

Ответ 2

Определенно ДА, (Не в чистом SQL) либо используют LAG (с 7.1.x) зависят от того, какую версию Vertica вы используете или создать пользовательский UDx (пользовательские расширения)

UDx в Java для доступа к предыдущей строке, которая действует как LAG только с одним шагом (производительность hastag #),  (github, полный примеров udx)

public class UdxTestFactory extends AnalyticFunctionFactory {

    @Override
    public AnalyticFunction createAnalyticFunction(ServerInterface srvInterface) {
        return new Test();
    }

    @Override
    public void getPrototype(ServerInterface srvInterface, ColumnTypes argTypes,
                             ColumnTypes returnType) {
        argTypes.addInt();
        argTypes.addInt();
        returnType.addInt();
    }

    @Override
    public void getReturnType(ServerInterface srvInterface, SizedColumnTypes argTypes,
                              SizedColumnTypes returnType) throws UdfException {
        returnType.addInt();
    }

    private class Test extends AnalyticFunction {

        @Override
        public void processPartition(ServerInterface srvInterface, AnalyticPartitionReader inputReader, AnalyticPartitionWriter outputWriter)
                throws UdfException, DestroyInvocation {

            SizedColumnTypes inTypes = inputReader.getTypeMetaData();
            ArrayList<Integer> argCols = new ArrayList<Integer>();

            inTypes.getArgumentColumns(argCols);

            outputWriter.setLongNull(0);

            while (outputWriter.next()) {
                long v1 = inputReader.getLong(argCols.get(0)); // previous row
                inputReader.next();
                long v2 = inputReader.getLong(argCols.get(0)); // curent row
                outputWriter.setLong(0, v2 - v1);
            }
        }

    }


}

скомпилировать и объединить скомпилированные классы в одну банку, назвав ее TestLib.jar для простоты

$ javac -classpath /opt/vertica/bin/VerticaSDK.jar /opt/vertica/sdk/BuildInfo.java UdxTestFactory.java -d . 
$ jar -cvf TestLib.jar com/vertica/sdk/BuildInfo.class com/vertica/JavaLibs/*.class

Загрузить библиотеку и функцию

CREATE OR REPLACE LIBRARY TestFunctions AS '/home/dbadmin/TestLib.jar' LANGUAGE 'JAVA';
CREATE OR REPLACE ANALYTIC FUNCTION lag1 AS LANGUAGE 'java' NAME 'com.vertica.JavaLibs.UdxTestFactory' LIBRARY TestFunctions;

И.. используйте его

SELECT 
    lag1(col1, null) OVER (ORDER BY col2) AS col1_minus_col2 
FROM ...