Виконання перетворень системи числення (исходники), Різне, Програмування, статті

У мережевих конференціях з SQL Server часто зустрічається питання про те, як виконується перетворення системи. Тобто користувач зберігає значення як рядкові величини, що містять числа в даній системі і хоче конвертувати їх в іншу систему числення. Як правило, користувачеві потрібно зберігати значення в недесяткових системі, коли програма працює з недесяткових величинами (наприклад, серійні номери, представлені по базі 36, двійкові бітові образи, що зберігаються в двійковій системі). Десяткова система використовує цифри від 0 до 9. N-розмірна система, менше ніж 10, використовує цифри від 0 до n – 1. Система більше ніж 10 використовує числа від 0 до 9 плюс алфавітні символи, що починаються з A. Наприклад, шістнадцяткова система використовує цифри 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 і символи від A до F, де A являє собою десяткове значення 10, B представляє 11, і так далі. Однак SQL Server не підтримує роботу cо значеннями, вираженими в недесяткових системі. Таким чином, виникають труднощі у зв’язку з необхідністю зберігання таких значень і виконання арифметичних маніпуляцій, на зразок обчислення результату виразу 1101 + 1010 в двійковій системі.


Нижче буде показано, як конвертувати з будь-якої системи величини до десяткового значенням так, щоб можна було застосовувати будь-які арифметичні обробки. Наступного разу я покажу, як конвертувати результат десяткової величини назад в обрану систему. Звичайна проблема для запитів на T-SQL полягає в тому, що доводиться писати багато логічних обробок. Навіть якщо в дійсності немає необхідності в конверторі бази даних, написати конвертор на T-SQL – хороша практика для шліфування прийомів роботи на T-SQL. Поставтеся до даної задачі як до вправи на логіку і спробуйте придумати власне рішення, перш ніж подивитися відповідь.


Перетворення в десяткову систему


Обрана символьний рядок, що представляє значення в деякій системі числення, і завдання полягає в конвертуванні введення до десяткового значенням типу даних bigint. Запустіть сценарій, описаний в Лістингу 1, Для створення таблиці T1 і заповніть її трьома значеннями, кожне у своїй системі числення. Поле id – це поле IDENTITY, яке виконує функції первинного ключа, val – символьний рядок, яка містить значення, і база – це основа системи числення. Необхідно написати код на T-SQL, який конвертує всі вхідні величини з T1 до цієї базу десятковим значенням (десяткова система). У Таблиці 1 показаний бажаний висновок. Спробуйте придумати рішення на основі набору, яке буде, ймовірно, більш ефективно, ніж рішення, засноване на ітераційному методі.


Перед тим, як описувати власне рішення, я спочатку поясню логіку після конвертації величин в даній системі до десяткового значення. Вступне десяткове значення v по базі b, яке містить n символів – це SUM ((перша цифра) × b 0 + (Друга цифра) × b 1 + (Третя цифра) × b 2 + … + (N-а цифра) t × b ( n -1)), Де перше число саме праве число, друге – друга цифра праворуч, і так далі. Наприклад, шістнадцяткове значення (шістнадцяткова система) 1F – це 15 × 160 + 1 × 161 = 15 + 16 = 31 в десятковій системі. Перше шістнадцяткове число F (читаємо справа наліво) дорівнює 15 у десятковій системі, і друге шістнадцяткове число 1 дорівнює 1 в десятковій системі.


Перший крок в обчисленні повинен розділяти кожне вхідне значення на окремі цифри справа наліво. Можна легко цього досягти, поєднуючи T1 з допоміжною таблицею чисел, яка створюється і заповнюється, якщо виконати код з Лістингу 2. Використовується умова зв’язування n <= LEN (val)


Напишіть такий вираз SELECT для витягання окремих цифр:

SUBSTRING(val,  LEN(val) – n + 1, 1)

Наприклад, значення 1F створить два результуючих рядки: одну з n дорівнює 1 і значенням F, і іншу з n рівним 2 і значенням 1.


Другий крок трохи хитріше. Тепер, коли обчислена числова позиція (n) і вилучено число з цієї позиції, обчислюємо десяткове значення позиції. Можна виконати це обчислення визначенням позиції символу витягнутого числа в межах рядка “0123456789ABCDE FGHIJKLMNOPQRSTUVWXYZ” – 1. Наприклад, число F є 16-м символом у вищезгаданій рядку; (16 – 1) дає його десяткове значення, 15. В T-SQL вираз для виконання цього обчислення наступне:

CHARINDEX(SUBSTRING  (val, LEN(val) – n + 1, 1),  “0123456789ABCDEFGHIJKLM NOPQRSTUVWXYZ”) – 1  AS decdigit

Фактично ви набираєте рядок символів як окремий рядок. Виконайте запит з Лістингу 3, Щоб пройти попередні два кроки, які розбивають кожне вхідне значення на окремі цифри і їх відповідні позиції і обчислюють десяткове значення кожної цифри. Таблиця 2 показує результати цього запиту.


Третій крок до вирішення проблеми – це множення десяткового числа (decdigit) на підставу в ступені позиція числа мінус 1: decdigit × підставу(Позиція-1). Четвертий і останній крок повинен групувати записи по id (група по всіх вихідних значень) і обчислювати суму результату обчислень, виконаних в третьому кроці.


Щоб виконати останні два кроки, створіть вторинну таблицю по запиту з лістингу 3. У зовнішньому запиті згрупуйте дані по id, значенням і системі і по кожній групі поверніть результат наступного вираження на T-SQL:

SUM(decdigit * POWER(CAST  (base AS bigint), pos-1))   AS decval

Підстава зберігається як звичайний цілочисельний тип даних int. Причина конвертації підстави до типу даних bigint полягає в тому, що функція POWER () повертає той же самий тип даних, що і тип даних перший параметр. Якщо ви хочете забезпечувати десяткові значення до найвищого можливого значення цілого числа (максимальне значення bigint), перший параметр для функції POWER () повинен бути типом даних bigint. В Лістингу 4 показано готове рішення, яке видає необхідний результат, що міститься в Таблиці 1.


Виділення логіки


Якщо необхідно виділити логіку перетворення, можна створити визначається користувачем функцію (UDF), яка приймає початкове значення і підстава як вхідні значення та повертає десяткове значення. У властивостях функції немає нічого особливого, крім факту, що запит виконується тільки за таблицею Nums. Замість багаторазових вступних значень в таблиці, схожої на T1, можна використовувати тільки одне вступне значення і підстава. Користувач визначає результуючий запит в операторі RETURN.


Виконайте код з Лістингу 5 і створіть функцію dbo.fn_basetodec (). Для перевірки функції викличте її і використовуйте значення 1F і підстава 16 в якості вступних значень:

SELECT dbo.fn_basetodec
(“1F”, 16);

В результаті виходить десяткове значення 31.


Тепер, коли є метод перетворення значення в будь заданій системі (аж до заснування 36) до десяткового числа, необхідно виконувати арифметичні операції над вступними значеннями в будь-яких даних системах. Наприклад, щоб обчислити результат додавання двох величин в двійковій системі, 1101 + 1010, просто виконайте

SELECT dbo.fn_basetodec(“1101”, 2)
+ dbo.fn_basetodec(“1010”, 2)

Цей код видає десятковий результат 23. Якщо потрібно конвертувати результуючі десяткове значення в двійкову систему, можна написати програму, яка конвертує значення з десяткової системи в двійкову систему або, ще краще, в будь-яку необхідну систему. У наступній статті я покажу, як написати такий конвертер.



Лістинг 1. Створення і заповнення таблиці T1

SET NOCOUNT ON;
USE tempdb;
GO
IF OBJECT_ID(“T1”) IS NOT NULL
DROP TABLE T1;
GO
CREATE TABLE T1
( id NOT NULL IDENTITY PRIMARY KEY,
val varchar(63) NOT NULL,
base int );
INSERT INTO T1 VALUES(“STELLAARTOIS”, 36);
INSERT INTO T1 VALUES(“1F”, 16);
INSERT INTO T1 VALUES(“1011”, 2);


Лістинг 2. Створення і заповнення допоміжної таблиці Nums

IF OBJECT_ID(“Nums”) IS NOT NULL DROP TABLE Nums;
CREATE TABLE Nums(n int NOT NULL);
SET NOCOUNT ON;
DECLARE @max AS int, @rc AS int;
SET @max = 8000;
SET @rc = 1;

BEGIN TRAN;
INSERT INTO Nums VALUES(1);
WHILE @rc * 2 <= @max
BEGIN
INSERT INTO Nums SELECT n + @rc FROM Nums;
SET @rc = @rc * 2;
END
INSERT INTO Nums SELECT n + @rc FROM Nums
WHERE n + @rc <= @max;

COMMIT TRAN;

ALTER TABLE Nums ADD PRIMARY KEY(n);




Лістинг 3. Поділ значіння на цифри і обчислення десяткового значення

SELECT id, val, base, n AS pos,
SUBSTRING(val, LEN(val) – n + 1, 1) AS digit,
CHARINDEX(SUBSTRING(val, LEN(val) – n + 1, 1),
“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”) – 1
AS decval
FROM T1 JOIN Nums
ON n <= LEN(val);


Лістинг 4. Запит, що повертає сконвертовані число в десятковій системі

SELECT id, val, base,
SUM(decdigit * POWER(CAST(base AS BIGINT), pos-1))
AS decval
FROM (SELECT id, val, base, n AS pos,
CHARINDEX(SUBSTRING(val, LEN(val) – n + 1, 1),
“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”) – 1
AS decdigit
FROM T1 JOIN Nums
ON n <= LEN(val)) AS D
GROUP BY id, val, base;


Лістинг 5. Функція, що повертає сконвертовані число в десятковій системі

CREATE FUNCTION dbo.fn_basetodec
(@val AS VARCHAR(63), @base AS int)
RETURNS BIGINT
AS
BEGIN
RETURN
(SELECT SUM(
(CHARINDEX(
SUBSTRING(@val, LEN(@val) – n + 1, 1),
“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”) – 1)
* POWER(CAST(@base AS BIGINT), n-1))
FROM Nums
WHERE n <= LEN(@val));
END
GO

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*