[英]How to emulate LPAD/RPAD with SQLite
我很好奇如何以最一般的方式正式模拟 SQLite 的 RPAD 和 LPAD 功能。 目标是能够做到
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
function 通常如何被仿真? 我迷失了各种可能性:
一个相关的问题:
复制自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
您也可以使用 PRINTF。
sqlite> SELECT PRINTF('%02d',5);
05
sqlite> SELECT PRINTF('%04d%02d',25,5);
002505
sqlite>
@user610650 解决方案的更简单版本,使用 hex() 而不是 quote(),除了字符填充外,还可以使用字符串填充:
X = padToLength
Y = padString
Z = expression
select
Z ||
substr(
replace(
hex(zeroblob(X)),
'00',
Y
),
1,
X - length(Z)
);
这里对你来说更讨厌:
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
功能。
JDBC/自定义函数方法(可能不适合您的具体情况,但可能能够适应)。 使用来自SqliteJDBC 自定义函数以及来自 Apache commons.lang.StringUtils 的rightPad和leftPad函数的灵感:
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)));
}
});
}
}
(未经测试,即兴发挥,不处理空值等,但应该概述这个想法......)
她是使用 CASE 用前导零填充 0-9 的简单解决方案。
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
我绝对没有 SQLite 的经验,实际上我与 SQLite3 db 交互的时间只有不到三天。 所以我不确定我的发现对你的要求有什么帮助。
我正在玩一些有趣的项目,即拥有所有可能的 11 位电话号码(3 位运营商前缀 + 8 位用户号码)。 我的目标是创建某种具有尽可能少的存储资源的数据库,但必须涵盖数据库上所有可能的数字。 所以我为 8 位订户创建了一个表,另一个表包含 3 位公司前缀。 最终数字将出现在连接两个表数据的视图中。 让我专注于 LOAD 问题。 由于订阅者表列是 INT,它是 0 到 99999999 条记录。 用户数少于 10000000 的简单加入失败; 任何低于 10000000 的订阅者订阅 ID 号都会显示为 XXXprefix+11,其中预期为 XXX000000+11。
在 SQLite 上使用 LPAD/RPAD 失败后,我找到了“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 需求。
干杯!
也许是这样的:
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 )
printf 也适用于空格:
SELECT 'text lpad 20 "'||printf("%020s", 'text')||'"' paddedtxt UNION
SELECT 'text rpad 20 "'||printf("%-020s", 'text')||'"' paddedtxt UNION
SELECT 'num lpad 20 "'||printf("%020d", 42)||'"' paddedtxt
结果到
num lpad 20 "00000000000000000042"
text lpad 20 " text"
text rpad 20 "text "
目标:使用可用的 sqlite 函数来模拟 ltrim
做法:(1)使用concat function "||" 在字符串的左侧添加零(或任何所需的填充字符),添加等于您想要剩余的字符数的零,然后在右侧添加零。 (2) 使用 substring 保持所需的字符数。
示例:将 page_number 填充为 integer 左侧为零,以在左侧填充五个字符零:
select
substring(('00000' || cast(page_number as text) || '0'), -1, -5)
来自分类 = xxx' 的页面
评论:substring 从 -1 开始时似乎忽略了最后一个字符,这就是为什么我在右边添加了一个零 - 所以它可以被忽略。 可能有一种更优雅的方式来做到这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.