#sql-server #string #tsql #count
#sql-сервер #строка #tsql #количество
Вопрос:
Мне нужен запрос или функция для подсчета 0 между 1 в строке.
Например:
String1 = '10101101' -> Result=3
String2 = '11111001101' -> Result=1
String3 = '01111111111' -> Result=1
Мне нужно искать только шаблон 101 или шаблон 01, если он находится в начале строки.
Комментарии:
1. Можем ли мы спросить, какую проблему вы пытаетесь решить здесь? Это просто головоломка?
2. Если строка начинается с,
01
то0
на самом деле это не «между»1
.3. какова максимальная длина строки?
4. Честно говоря, кажется, что это было бы лучше с чем-то, что поддерживает сопоставление шаблонов РЕГУЛЯРНЫХ выражений.
Ответ №1:
Вы можете попытаться разложить входные строки с помощью SUBTRING()
и таблицы чисел:
SELECT
String, COUNT(*) AS [101Count]
FROM (
SELECT
v.String,
SUBSTRING(v.String, t.No - 1, 1) AS PreviousChar,
SUBSTRING(v.String, t.No, 1) AS CurrentChar,
SUBSTRING(v.String, t.No 1, 1) AS NextChar
FROM (VALUES
('10101101'),
('11111001101'),
('01111111111')
) v (String)
CROSS APPLY (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) t (No)
) cte
WHERE
CASE WHEN PreviousChar = '' THEN '1' ELSE PreviousChar END = '1' AND
CurrentChar = '0' AND
NextChar = '1'
GROUP BY String
Результат:
String 101Count
10101101 3
11111001101 1
01111111111 1
Примечания:
Таблица с псевдонимом v
является исходной таблицей, таблица с псевдонимом t
является таблицей чисел. Если входные строки содержат более 10 символов, используйте соответствующую таблицу чисел (tally).
Ответ №2:
— Это преобразует «111101101010111» в «01101010» и «011101000» в «01110»
regexp_replace(field, '^1*(.*)1*0*$', '1')
— Это преобразует «01101010» в «0000»
regexp_replace(field, '1', '')
— Это подсчитывает длину строки, возвращая 4 для ‘0000’:
LENGTH(field)
— Собрать все вместе:
LENGTH(
regexp_replace(
regexp_replace(field, '^1*(.*)1*0*$', '1')
, '1', '')
)
Различные или более сложные случаи требуют модификации регулярного выражения.
Обновить
Теперь я вижу, что под «нулями между 1 с» вы имеете в виду последовательности «101». Это сложнее из-за возможности наличия «10101». Предположим, вы хотите посчитать это как 2:
-
замените 101 на 11011. Теперь 10101 станет либо 1101101, либо 1101111011. В любом случае у вас есть последовательность «101», которая находится далеко друг от друга, и все еще есть только две из них.
-
замените все 101 с на ‘X’. Теперь у вас есть 1X11X1
-
замените [01] пустой строкой. Теперь у вас есть XX.
-
используйте длину для подсчета X.
Любую дополнительную специальную последовательность, такую как «01» в начале, вы можете преобразовать в первую очередь с помощью «X1» («10» в конце станет «1X»), которая затем аккуратно сложится обратно в описанном выше рабочем процессе.
Ответ №3:
Используя LIKE
оператор с %
, вы можете решить, как искать конкретную строку. В этом SQL-запросе я говорю, что хочу, чтобы каждая запись начиналась как 101
или 01
.
SELECT ColumnsYouWant FROM TableYouWant
WHERE ColumnYouWant LIKE '101%' OR '01%';
Вы можете просто COUNT
ColumnYouWant
, вот так:
SELECT COUNT(ColumnYouWant) FROM TableYouWant
WHERE ColumnYouWant LIKE '101%' OR '01%';
Или вы можете использовать метод вашего внутреннего языка для count
результатов, возвращаемых первым запросом. Этот count
метод будет зависеть от языка, с которым вы работаете.
Документация по SQL для LIKE
:https://www.w3schools.com/sql/sql_like.asp
Документация по SQL для COUNT
; https://www.w3schools.com/sql/sql_count_avg_sum.asp
Комментарии:
1. Как это «подсчитывает» экземпляры шаблонов в строке?
Ответ №4:
Другие решения не учитывают все символы (максимум 11, из показанных примеров)
Данные
drop table if exists #tTEST;
go
select * INTO #tTEST from (values
(1, '10101101'),
(2, '11111001101'),
(3, '01111111111')) V(id, string);
Запрос
;with
split_cte as (
select id, n, substring(t.string, v.n, 1) subchar
from #tTEST t
cross apply (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),
(11),(12),(13),(14),(15),(16),(17),(18),(19),(20)) v(n)
where v.n<=len(t.string)),
lead_lag_cte as (
select id, n, lead(subchar, 1, 9) over (partition by id order by n) lead_c, subchar,
lag(subchar, 1, 9) over (partition by id order by n) lag_c
from split_cte)
select id, sum(case when (lead_c=1 and lag_c=9) then 1 else
case when (lead_c=1 and lag_c=1) then 1 else 0 end end) zero_count
from lead_lag_cte
where subchar=0
group by id;
Результаты
id zero_count
1 3
2 1
3 1
Ответ №5:
Другой способ, возможно, быстрее:
DECLARE @T TABLE (ID INT, STRING VARCHAR(32));
INSERT INTO @T
VALUES (1, '10101101'),
(2, '11111001101'),
(3, '01111111111');
SELECT *, LEN(STRING) - LEN(REPLACE(STRING, '0', '')) AS NUMBER_OF_ZERO
FROM @T
Результат:
ID STRING NUMBER_OF_ZERO
----------- -------------------------------- --------------
1 10101101 3
2 11111001101 3
3 01111111111 1
Ответ №6:
select (len(replace('1' x, '101', '11011')) - len(replace(replace('1' x, '101', '11011'), '101', '')))/3
from
(
values
('10101101'),
('11111001101'),
('01111111111'),
('01010101010101010101')
) v(x);