【问题标题】:MS SQL to SQLite syntaxMS SQL 到 SQLite 语法
【发布时间】:2021-04-10 10:02:53
【问题描述】:

首先,我正在努力实现以下目标:

我首先使用 MS SQL 来确定如何将标签对齐在一起。

如果您想重新创建未规范化的表,这里是架构。

CREATE TABLE unnormalized(
  vendor_tag varchar(200),
  vendor_tag_name varchar(200),
  vendor_id int
  );
  
 INSERT INTO unnormalized
VALUES
('5,8,30,24','Burgers,Desserts,Fries,Salads',1),
('5','Burgers',2),
('8,42','Desserts,Mexican',3),
('1,5,30,16','American,Burgers,Fries,Sandwiches',4),
('1,5,30,16','American,Burgers,Fries,Sandwiches',5);

这是规范化表的代码

SELECT
    --*
    DISTINCT CAST(tag_id AS INT) as tag_id ,tag_name
FROM unnormalized 
CROSS APPLY 
(
    (SELECT 
        value as tag_id,
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rn
     FROM STRING_SPLIT(vendor_tag,',') 
    ) a1
    INNER JOIN 
    (SELECT 
        value as tag_name,
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rn
     FROM STRING_SPLIT(vendor_tag_name,',') 
     ) a2
    ON a1.rn = a2.rn
) 
ORDER BY tag_id

现在我正在尝试使用 SQLite 重写此代码。但是,SQLite 中没有一些差异,例如“CROSS APPLY”和“STRING_SPLIT”。我环顾四周,发现 CROSS APPLY 可能类似于 SQLite 中的“CROSS JOIN”,并且可能使用类似这样的东西在它找到的第一个逗号处分隔字符串??

WITH split(vendor_id, vendor_tag, str) AS (
    SELECT vendor_id, '', vendor_tag||',' FROM unnormalized
    UNION ALL SELECT vendor_id,
    substr(str, 0, instr(str, ',')),
    substr(str, instr(str, ',')+1)
    FROM split 
    WHERE str
) 

SELECT vendor_id, vendor_tag
FROM split 
WHERE vendor_tag
ORDER BY vendor_id;

【问题讨论】:

  • 修复你的数据模型!不要在单个列中存储多个值!不要将数字存储为字符串!
  • 这个表不只是“未标准化”,它违反了最基本的设计规则——每个单元格都应该包含一个 atomic 值。如果您使用正确的模式,您将不会有任何问题。即使在具有数组的数据库中,不同数组的元素之间也没有关系
  • 对于 SQLite,通过拆分 SQL 中的值,您将一无所获。 SQLite 是一个嵌入式 数据库,这意味着引擎由您的应用程序托管和运行,使用您的应用程序的 RAM。使用客户端应用程序的语言拆分字符串比尝试在 SQLite 中执行相同操作要快得多
  • @Panagiotis Kanavos 该表是我在 kaggle 中找到的 csv 文件中的数据,并且正在做一些练习以将数据填充到数据库中
  • 你为什么使用这样的模式?你试图解决什么问题?不是速度或可扩展性——这个模式非常慢,根本无法扩展。每个查询都必须扫描整个表,并且不能使用任何索引。空间?这可能比具有整数 ID 的适当表使用 更多 空间,即使对于少数供应商也是如此。如果你有很多供应商,你可以在 SQL Server 中使用表压缩

标签: sql sql-server sqlite


【解决方案1】:

在 SQLite 中,您可以使用递归 CTE:

WITH cte AS (
  SELECT 
    vendor_tag, 
    vendor_tag_name,
    SUBSTR(vendor_tag, 1, INSTR(vendor_tag || ',', ',') - 1) col1,
    SUBSTR(vendor_tag_name, 1, INSTR(vendor_tag_name || ',', ',') - 1) col2
  FROM unnormalized 
  UNION ALL 
  SELECT 
    SUBSTR(vendor_tag, LENGTH(col1) + 2), 
    SUBSTR(vendor_tag_name, LENGTH(col2) + 2), 
    SUBSTR(SUBSTR(vendor_tag, LENGTH(col1) + 2), 1, INSTR(SUBSTR(vendor_tag, LENGTH(col1) + 2) || ',', ',') - 1),
    SUBSTR(SUBSTR(vendor_tag_name, LENGTH(col2) + 2), 1, INSTR(SUBSTR(vendor_tag_name, LENGTH(col2) + 2) || ',', ',') - 1)
  FROM cte  
  WHERE LENGTH(vendor_tag) AND LENGTH(vendor_tag_name)
)
SELECT DISTINCT col1 vendor_tag, col2 vendor_tag_name
FROM cte
WHERE NOT (INSTR(col1, ',') OR INSTR(col2, ',')) AND (LENGTH(col1) AND LENGTH(col2))
ORDER BY vendor_tag + 0

请参阅demo
结果:

> vendor_tag | vendor_tag_name
> :--------- | :--------------
> 1          | American       
> 5          | Burgers        
> 8          | Desserts       
> 16         | Sandwiches     
> 24         | Salads         
> 30         | Fries          
> 42         | Mexican    

【讨论】:

  • 哇这个好用,谢谢!!目前我还没有对递归 CTE 进行太多研究,而且我在阅读代码时有些吃力。但我会进一步研究代码!
  • SUBSTR(vendor_tag, LENGTH(col1) + 2), SUBSTR(vendor_tag_name, LENGTH(col2) + 2), SUBSTR(SUBSTR(vendor_tag, LENGTH(col1) + 2), 1, INSTR(SUBSTR(vendor_tag, LENGTH(col1) + 2) || ',', ',') - 1), SUBSTR(SUBSTR(vendor_tag_name, LENGTH(col2) + 2), 1, INSTR(SUBSTR(vendor_tag_name, LENGTH(col2) + 2) || ',', ',') - 1) 能否对这部分代码提供更多见解?
  • @Q.T 递归 CTE 实际上是一个循环(类似于其他编程语言中的 while 循环)。在每次迭代中,我都会将字符串的一部分放在第一个 , 上,在下一次迭代中,我会将剩余字符串的部分放在下一个 , 上,依此类推。这就是我使用 INSTR()、SUBSTR() 等字符串函数的原因。
  • 您好,另一个问题。我将如何使用该代码将其插入此表中? CREATE TABLE IF NOT EXISTS tag ( tag_id INTEGER PRIMARY KEY, tag_name TEXT, );
  • @Q.T 检查这个:dbfiddle.uk/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多