Синтаксис MS SQL для SQLite

#sql #sql-server #sqlite

#sql #sql-сервер #sqlite

Вопрос:

Прежде всего, я пытаюсь добиться следующего: введите описание изображения здесь

Сначала я использовал 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. Однако есть несколько отличий, таких как ‘CROSS APPLY’ и ‘STRING_SPLIT’, отсутствующих в SQLite. Я огляделся и обнаружил, что ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ, возможно, похоже на «ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ» в SQLite и, возможно, использует что-то подобное, чтобы отделить строку от первой найденной запятой??

 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;
 

Комментарии:

1. Исправьте свою модель данных! Не храните несколько значений в одном столбце! Не храните числа в виде строк!

2. Эта таблица не просто «ненормализована», она нарушает самое основное правило проектирования — каждая ячейка должна содержать атомарное значение. Если бы вы использовали правильную схему, у вас не было бы никаких проблем. Даже в базах данных, содержащих массивы, нет никакой связи между элементами разных массивов

3. Что касается SQLite, вы вообще ничего не получаете, разделяя значения в SQL. SQLite — это встроенная база данных, что означает, что движок размещается и запускается вашим приложением, используя оперативную память вашего приложения. Намного быстрее разделить строки на языке вашего клиентского приложения, чем пытаться сделать то же самое в SQLite

4. @Panagiotis Kanavos Таблица представляет собой данные из файла csv, который я нашел в kaggle и выполнял некоторые упражнения для заполнения данных в базу данных

5. Почему вы использовали такую схему? Какую проблему вы пытались исправить? Не скорость или масштабируемость — эта схема чрезвычайно медленная и вообще не масштабируется. Каждый запрос должен сканировать всю таблицу и не может использовать какие-либо индексы. Пробел? Вероятно, это занимает больше места, чем правильная таблица с целочисленными идентификаторами, даже для небольшого числа поставщиков. Если у вас много поставщиков, вы можете использовать сжатие таблиц в SQL Server

Ответ №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
 

Посмотрите демонстрацию.
Результаты:

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

Комментарии:

1. Вау, это работает, спасибо!! На данный момент я мало изучал рекурсивный CTE, и мне немного сложно читать код. Но я изучу код немного дальше!

2. 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) Не могли бы вы дать немного больше информации об этой части кода?

3. @Q.T Рекурсивный CTE на самом деле представляет собой цикл (что-то вроде цикла while в других языках программирования). На каждой итерации я получаю часть строки до первой , , а на следующей итерации я получаю часть оставшейся строки до следующей , и так далее. Вот почему я использую строковые функции, такие как INSTR(), SUBSTR() .

4. Привет, еще один вопрос. Как я могу использовать этот код, чтобы вставить его в эту таблицу? CREATE TABLE IF NOT EXISTS tag ( tag_id INTEGER PRIMARY KEY, tag_name TEXT, );

5. @Q.T проверьте это: dbfiddle.uk /…