Как эмулировать LPAD / RPAD с SQLite - PullRequest
12 голосов
/ 05 июля 2011

Мне любопытно, как формально, эмулировать функции RPAD и LPAD для SQLite, в наиболее общем виде.Цель состоит в том, чтобы иметь возможность сделать

LPAD(column, character, repeat)
RPAD(column, character, repeat)

Для столбцов непостоянных таблиц column, character, repeat.Если бы character и repeat были известными постоянными, то это было бы хорошим, жизнеспособным решением:

Но что, если вышеприведенное должно бытьвыполняется следующим образом:

SELECT LPAD(t.column, t.character, t.repeat) FROM t
SELECT LPAD(t.column, some_function(), some_other_function()) FROM t
SELECT LPAD(t.column, :some_bind_variable, :some_other_bind_variable) FROM t

Как вообще можно эмулировать эту функцию LPAD?Я потерян с возможностями:

Смежный вопрос:

Ответы [ 7 ]

20 голосов
/ 28 января 2016

Скопировано с http://verysimple.com/2010/01/12/sqlite-lpad-rpad-function/

-- the statement below is almost the same as
-- select lpad(mycolumn,'0',10) from mytable

select substr('0000000000' || mycolumn, -10, 10) from mytable

-- the statement below is almost the same as
-- select rpad(mycolumn,'0',10) from mytable

select substr(mycolumn || '0000000000', 1, 10) from mytable
4 голосов
/ 18 июля 2012

Вот вам еще одна неприятность:

X = padToLength
Y = padString
Z = expression

RPAD (для LPAD вместо этого Z объединяется:

select 
    Z || 
    substr(
        replace(
            replace(
                substr(
                    quote(zeroblob(((X - length(Z) - 1 + length(Y)) / length(Y) + 1) / 2)), 
                    3
                ), 
                "'", 
                ""
            ), 
            "0", 
            Y
        ),
        1,
        (X - length(Z))
    )

Примеры:

sqlite> select "foo" || replace(replace(substr(quote(zeroblob((2 + 1) / 2)), 3, (2 - length("foo"))), "'", ""), "0", "W");
foo
sqlite> select "foo" || replace(replace(substr(quote(zeroblob((7 + 1) / 2)), 3, (7 - length("foo"))), "'", ""), "0", "W");
fooWWWW

Sqlite должен быть довольно легковесным, поэтому я должен несколько не согласиться с вашим комментарием о том, что он «удивлен» отсутствием функциональности.Однако я согласен с тем, что должен быть более простой способ заполнения, хотя бы потому, что существуют функции trim.

2 голосов
/ 10 августа 2018

Более простая версия решения @ user610650, использующая hex () вместо quote () и работающая с заполнением строк в дополнение к заполнению символов:

X = padToLength
Y = padString
Z = expression

select
    Z ||
    substr(
        replace(
            hex(zeroblob(X)),
            '00',
            Y
        ),
        1,
        X - length(Z)
    );
1 голос
/ 27 ноября 2013

Это простое решение для заполнения 0-9 с ведущим нулем с помощью CASE.

sqlite> select id,week,year from bulletin where id = 67;
67|2|2014

select id,CASE WHEN length(week) = 2 THEN week 
               ELSE '0'||week 
          END AS week,year from bulletin where id = 67;
67|02|2014
1 голос
/ 22 июля 2012

Подход JDBC / пользовательских функций (может не подходить в вашем конкретном случае, но может быть адаптирован). Использует вдохновение из пользовательских функций SqliteJDBC и rightPad и leftPad функций из Apache commons.lang.StringUtils:

import java.sql.*;
import org.sqlite.Function;

public class Test 
{
  public static void main(String[] args) 
  {
    Connection conn = getConnection();

    conn.createStatement().execute("SELECT LPAD(t.column, t.character, t.repeat) FROM t");
    conn.createStatement().execute("SELECT RPAD(t.column, t.character, t.repeat) FROM t");

    conn.close();
  }

  public static Connection getConnection() 
  {
    Class.forName("org.sqlite.JDBC");
    Connection conn = DriverManager.getConnection("jdbc:sqlite:");

    /* Left Padding UDF  */
    Function.create(conn, "LPAD", new Function() 
      {
        protected void xFunc() throws SQLException 
        {
            String text = value_text(0);
            /* uses first character of supplied padding */
            char paddingCharacter = value_text(1).charAt(0);
            int repeat = value_int(2);

            int padLength = repeat - text.length();
            if(padLength <= 0)
            {
               result(text);
            }

            char[] padding = new char[padLength];
            Array.fill(padding, paddingCharacter);
            result(new String(padding).append(text));
        }
    });

    /* Right Padding UDF  */
    Function.create(conn, "RPAD", new Function() 
      {
        protected void xFunc() throws SQLException 
        {
            String text = value_text(0);
            /* uses first character of supplied padding */
            char paddingCharacter = value_text(1).charAt(0);
            int repeat = value_int(2);

            int padLength = repeat - text.length();
            if(padLength <= 0)
            {
               result(text);
            }

            char[] padding = new char[padLength];
            Array.fill(padding, paddingCharacter);
            result(text.append(new String(padding)));
        }
    });
  }
}

(Не проверено, без манжеты, не обрабатывает нули и т. Д., Но следует изложить идею ...)

0 голосов
/ 01 октября 2018

У меня абсолютно нет опыта работы с SQLite, фактически мое время взаимодействия с базой данных SQLite3 составляет менее трех дней. Поэтому я не уверен, что мои выводы могли бы помочь вашему требованию.

Я играю с забавным проектом, в котором есть все возможные 11-значные телефонные номера (3-значный префикс оператора + 8-значный номер абонента). Моя цель состояла в том, чтобы создать какую-то базу данных с минимально возможным ресурсом хранения, но я должен был покрыть все возможные числа в базе данных. Поэтому я создал одну таблицу для 8-значного абонента, а другая таблица содержит 3-значный префикс компании. Окончательное число появится на экране, соединяя две таблицы данных. Позвольте мне сосредоточиться на проблеме загрузки. Поскольку столбец таблицы подписчиков - INT, то это от 0 до 99999999 отдельных записей. Ошибка простого соединения для номера абонента, имеющего менее 10000000; Любой номер подписки подписчика стоимостью 10000000 показывает XXXprefix + 11, где ожидается XXX000000 + 11.

После сбоя LPAD / RPAD на SQLite я обнаружил "SUBSTR"!

Посмотрите на запрос ниже:

CREATE TABLE subs_num (
subscriber_num integer PRIMARY KEY
);

INSERT INTO subs_num values ('1');
INSERT INTO subs_num values ('10');
INSERT INTO subs_num values ('100');
INSERT INTO subs_num values ('1000');

SELECT subscriber_num from subs_num;

SELECT SUBSTR('00000000' || subscriber_num, -8, 8) AS SUBSCRIB_ID FROM subs_num;

Теперь я думаю, что вы можете использовать SUBSTR для своих нужд LPAD / RPAD.

Ура!

0 голосов
/ 05 июля 2011

Может быть так:

  • LPAD(@orig_text, @padding_char, @padding_length):

    SELECT
      SUBSTR(
        REPLACE(
          CAST(ZEROBLOB(@padding_length) AS TEXT),
          CAST(ZEROBLOB(1) AS TEXT),
          @padding_char
        ) + @orig_text,
        -@padding_length,
        @paadding_length
      )
    
  • RPAD(@orig_text, @padding_char, @padding_length):

    SELECT
      SUBSTR(
        @orig_text + REPLACE(
          CAST(ZEROBLOB(@padding_length) AS TEXT),
          CAST(ZEROBLOB(1) AS TEXT),
          @padding_char
        ),
        1,
        @padding_length
      )
    
...