TSQL – how to find if a column has a space char(32)
?
select *
from [sometable]
where CHARINDEX(' ', [somecolumn]) > 0
doesn’t work? Any ideas?
FallenAngel
18k15 gold badges82 silver badges113 bronze badges
asked Jul 25, 2009 at 2:22
2
You have to rtrim CHAR columns.
CHAR columns are padded with spaces on the right up to the maximum length.
RTRIM helps to avoid false positives when storing strings that are shorter than the maximum length.
select * from [table] where rtrim(col) like '% %'
create table dropme
(foo char(32))
insert into dropme values('nospaces')
insert into dropme values('i have a space')
insert into dropme values('space bar')
select replace(foo,' ','|') from dropme
where foo like '% %'
nospaces
i|have|a|space
space|bar
select replace(foo,' ','|') from dropme
where rtrim(foo) like '% %'
i|have|a|space
space|bar
answered Jul 25, 2009 at 2:41
JoeJoe
41.3k20 gold badges104 silver badges125 bronze badges
2
The following example should illustrate how you can achieve this.
create table #tableTest
(
someData varchar(100) not null
);
insert into #tableTest(someData) values('dsadsa');
insert into #tableTest(someData) values('fdssf 432423');
insert into #tableTest(someData) values('432423fsdv');
insert into #tableTest(someData) values('321 jhlhkj 543');
select *
from #tableTest;
select *
from #tableTest
where charindex(char(32),someData) > 0;
drop table #tableTest;
answered Jul 25, 2009 at 6:25
John SansomJohn Sansom
40.9k9 gold badges72 silver badges84 bronze badges
What do you mean by “doesn’t work”? Both ways work for me:
SELECT ''''+a+'''' FROM(
SELECT 'asd fgh' AS a UNION ALL
SELECT ' fgh' AS a UNION ALL
SELECT 'asd ' AS a UNION ALL
SELECT 'asfdg') As t
WHERE a LIKE '% %'
---------
'asd fgh'
' fgh'
'asd '
SELECT ''''+a+'''' FROM(
SELECT 'asd fgh' AS a UNION ALL
SELECT ' fgh' AS a UNION ALL
SELECT 'asd ' AS a UNION ALL
SELECT 'asfdg') As t
WHERE CHARINDEX(' ', a) > 0
---------
'asd fgh'
' fgh'
'asd '
answered Jul 25, 2009 at 2:39
A-KA-K
16.7k8 gold badges53 silver badges71 bronze badges
1
The following worked for me:
PrdPicture LIKE '%'+char(160)+'%'
Martin Evans
45.4k17 gold badges79 silver badges94 bronze badges
answered Jul 6, 2017 at 6:23
PratheeskumarPratheeskumar
4031 gold badge4 silver badges8 bronze badges
Given you’ve not really explained what the problem is…
Are you looking for hardspace (nbsp)
, CHAR(160)
? Or tab CHAR(9)
?
These can look like spaces but aren’t
FallenAngel
18k15 gold badges82 silver badges113 bronze badges
answered Jul 25, 2009 at 9:03
gbngbn
420k81 gold badges584 silver badges674 bronze badges
0
Use below query:
SELECT UniqueName
FROM employee
WHERE employeeName LIKE '% %'
answered Aug 23, 2018 at 15:53
select * from [sometable] where somecolumn like '% %'
FallenAngel
18k15 gold badges82 silver badges113 bronze badges
answered Jul 25, 2009 at 2:24
KellCOMnetKellCOMnet
1,8393 gold badges16 silver badges27 bronze badges
3
I had the exact same question as worded, though I was looking to see if the column had a space vs being null. This worked for me:
SELECT UniqueName
FROM employee
WHERE ascii(employeeName) = 32
The intuitive query doesn’t work; below returns all null rows as well:
SELECT UniqueName
FROM employee
WHERE employeeName = ' '
answered Apr 30, 2020 at 8:58
Как узнать есть ли пробелы в строке данных или строке запроса клиента через PostgreSQL?
Мы напишем функцию g4. У нас схема называется test1. Внутри тела функции будет производиться сопоставление на наличие пробелов. Проще всего это делать регулярными выражениями, которые работают практически во всех языках программирования одинаково.
Эта функция будет возвращать логическое значение TRUE или FALSE если встретит пробел в строке.
-- Добавляем язык 'plpgsql' -- Добавляем СТАРТ (BEGIN) и ФИНИШ (END) CREATE OR REPLACE FUNCTION test1.g4(str text) RETURNS boolean LANGUAGE 'plpgsql' AS $BODY$ BEGIN RETURN str ~ ' '; END; $BODY$;
Символ тильды «~» означает, что шаблон регулярного выражения будет учитывать регистр символов в строке.
У классического клавиатурного пробела нет понятия регистра, поэтому можно использовать два варианта написани:
SELECT 'bla bla' ~ ' '; или SELECT 'bla bla' ~* ' ';
Пример работы функции
SELECT test1.g4('bla bla bla'); -- true SELECT test1.g4('ffgghh'); -- false
Скриншоты:
Как удалить эту функцию?
DROP FUNCTION test1.g4(str text);
Зачем мы проверяем на наличие пробелов в строке?
Почти всегда требуется проверка корректности вводимых данных. Таблицы в PostgreSQL устроены таким образом, что определённый столбец ожидает определённый тип данных и никак иначе. Если мы говорим, что в столбце А храним URL-адреса, то нам не нужны строки с рецептами клубничного варенья. URL-адреса имеют характерный индивидуальный синтаксис, который можно легко отличить от других данных. Один из признаков URL — отсутствие символов пробела.
Задача функций — проверять валидность (корректность) данных перед остальными операциями CRUD (Create, Read, Update, Delete).
Информационные ссылки
PostgreSQL | Проверка содержимого строки перед вставкой в таблицу по условию
Сайт СУБД PostgreSQL — https://www.postgresql.org
Команды SQL — https://postgrespro.ru/docs/postgresql/14/sql-commands
Команда CREATE FUNCTION — https://postgrespro.ru/docs/postgresql/14/sql-createfunction
Команда SELECT — https://postgrespro.ru/docs/postgresql/14/sql-select
Раздел «9.4. Строковые функции и операторы» — https://postgrespro.ru/docs/postgresql/14/functions-string
Раздел «9.7.3. Регулярные выражения POSIX» — https://postgrespro.ru/docs/postgresql/14/functions-matching#FUNCTIONS-POSIX-REGEXP
Раздел «43.6. Управляющие структуры» — https://postgrespro.ru/docs/postgresql/14/plpgsql-control-structures
Графический интерфейс pgAdmin — https://www.pgadmin.org
Я нашел принятый ответ немного медленнее:
SELECT col FROM tbl WHERE col LIKE '% ';
против этой техники:
SELECT col FROM tbl WHERE ASCII(RIGHT([value], 1)) = 32;
Идея состоит в том, чтобы получить последний символ, но сравнить его ASCII
код с ASCII
код пробела вместо этого только с ' '
(Космос). Если мы будем использовать только ' '
пробел, пустая строка даст истину:
DECLARE @EmptyString NVARCHAR(12) = '';
SELECT IIF(RIGHT(@EmptyString, 1) = ' ', 1, 0); -- this returns 1
Вышесказанное связано с тем, что Microsoft реализация сравнения строк.
Итак, как быстро?
Вы можете попробовать следующий код:
CREATE TABLE #DataSource
(
[RowID] INT PRIMARY KEY IDENTITY(1,1)
,[value] NVARCHAR(1024)
);
INSERT INTO #DataSource ([value])
SELECT TOP (1000000) 'text ' + CAST(ROW_NUMBER() OVER(ORDER BY t1.number) AS VARCHAR(12))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
UPDATE #DataSource
SET [value] = [value] + ' '
WHERE [RowID] = 100000;
SELECT *
FROM #DataSource
WHERE ASCII(RIGHT([value], 1)) = 32;
SELECT *
FROM #DataSource
WHERE [value] LIKE '% ';
На моей машине разница составляет около 1 секунды:
Я тестировал его на таблице с 600 тыс. Строк, но большего размера, а разница была более 8 секунд. Итак, насколько быстро будет зависеть от данных вашего реального дела.
Я хотел бы найти первый «пробел» в столбце счетчика в таблице SQL. Например, если есть значения 1,2,4 и 5, я бы хотел узнать 3.
Я, конечно, могу привести значения в порядок и просмотреть их вручную, но я хотел бы знать, есть ли способ сделать это в SQL.
Кроме того, это должен быть вполне стандартный SQL, работающий с разными СУБД.
person
Touko
schedule
21.08.2009
source
источник
Ответы (18)
В MySQL
и PostgreSQL
:
SELECT id + 1
FROM mytable mo
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
ORDER BY
id
LIMIT 1
In SQL Server
:
SELECT TOP 1
id + 1
FROM mytable mo
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
ORDER BY
id
In Oracle
:
SELECT *
FROM (
SELECT id + 1 AS gap
FROM mytable mo
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
ORDER BY
id
)
WHERE rownum = 1
ANSI
(работает везде, наименее эффективно):
SELECT MIN(id) + 1
FROM mytable mo
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
Системы, поддерживающие функции раздвижного окна:
SELECT -- TOP 1
-- Uncomment above for SQL Server 2012+
previd
FROM (
SELECT id,
LAG(id) OVER (ORDER BY id) previd
FROM mytable
) q
WHERE previd <> id - 1
ORDER BY
id
-- LIMIT 1
-- Uncomment above for PostgreSQL
person
Quassnoi
schedule
21.08.2009
Все ваши ответы работают нормально, если у вас есть первое значение id = 1, иначе этот пробел не будет обнаружен. Например, если значения идентификатора вашей таблицы 3,4,5, ваши запросы вернут 6.
Я сделал что-то вроде этого
SELECT MIN(ID+1) FROM (
SELECT 0 AS ID UNION ALL
SELECT
MIN(ID + 1)
FROM
TableX) AS T1
WHERE
ID+1 NOT IN (SELECT ID FROM TableX)
person
Ruben
schedule
12.09.2012
На самом деле нет чрезвычайно стандартного способа SQL для этого, но с некоторой формой ограничивающего предложения вы можете сделать
SELECT `table`.`num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
LIMIT 1
(MySQL, PostgreSQL)
or
SELECT TOP 1 `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
(SQL-сервер)
or
SELECT `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
AND ROWNUM = 1
(Оракул)
person
chaos
schedule
21.08.2009
Первое, что пришло в голову. Не уверен, что это вообще хорошая идея, но должно сработать. Предположим, что таблица t
, а столбец c
:
SELECT t1.c+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL ORDER BY gap ASC LIMIT 1
Изменить: Это может быть на один тик быстрее (и короче!):
SELECT min(t1.c)+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL
person
Michael Krelin – hacker
schedule
21.08.2009
Это работает в SQL Server – не может проверить это в других системах, но кажется стандартным …
SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1))
Вы также можете добавить начальную точку к предложению where …
SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1)) AND ID > 2000
Итак, если у вас были 2000, 2001, 2002 и 2005 годы, а 2003 и 2004 не существовали, он вернет 2003.
person
Mayo
schedule
21.08.2009
Следующее решение:
- предоставляет тестовые данные;
- внутренний запрос, который производит другие пробелы; и
- он работает в SQL Server 2012.
Последовательно пронумеровывает упорядоченные строки в предложении «с», а затем повторно использует результат дважды с внутренним соединением по номеру строки, но смещением на 1, чтобы сравнить предыдущую строку со строкой после, глядя для идентификаторов с пробелом больше 1. Больше, чем просили, но более широко применимо.
create table #ID ( id integer );
insert into #ID values (1),(2), (4),(5),(6),(7),(8), (12),(13),(14),(15);
with Source as (
select
row_number()over ( order by A.id ) as seq
,A.id as id
from #ID as A WITH(NOLOCK)
)
Select top 1 gap_start from (
Select
(J.id+1) as gap_start
,(K.id-1) as gap_end
from Source as J
inner join Source as K
on (J.seq+1) = K.seq
where (J.id - (K.id-1)) <> 0
) as G
Внутренний запрос производит:
gap_start gap_end
3 3
9 11
Внешний запрос производит:
gap_start
3
person
wwmbes
schedule
07.02.2019
Внутреннее присоединение к представлению или последовательности, имеющей все возможные значения.
Нет стола? Сделайте стол. Я всегда держу под рукой пустышку только для этого.
create table artificial_range(
id int not null primary key auto_increment,
name varchar( 20 ) null ) ;
-- or whatever your database requires for an auto increment column
insert into artificial_range( name ) values ( null )
-- create one row.
insert into artificial_range( name ) select name from artificial_range;
-- you now have two rows
insert into artificial_range( name ) select name from artificial_range;
-- you now have four rows
insert into artificial_range( name ) select name from artificial_range;
-- you now have eight rows
--etc.
insert into artificial_range( name ) select name from artificial_range;
-- you now have 1024 rows, with ids 1-1024
Потом,
select a.id from artificial_range a
where not exists ( select * from your_table b
where b.counter = a.id) ;
person
tpdi
schedule
21.08.2009
Это объясняет все, о чем говорилось до сих пор. Он включает 0 в качестве начальной точки, которая будет использоваться по умолчанию, если также не существует никаких значений. Я также добавил соответствующие места для других частей многозначного ключа. Это было проверено только на SQL Server.
select
MIN(ID)
from (
select
0 ID
union all
select
[YourIdColumn]+1
from
[YourTable]
where
--Filter the rest of your key--
) foo
left join
[YourTable]
on [YourIdColumn]=ID
and --Filter the rest of your key--
where
[YourIdColumn] is null
person
Carter Medlin
schedule
02.07.2013
Для PostgreSQL
Пример использования рекурсивного запроса.
Это может быть полезно, если вы хотите найти пробел в определенном диапазоне (он будет работать, даже если таблица пуста, тогда как другие примеры – нет)
WITH
RECURSIVE a(id) AS (VALUES (1) UNION ALL SELECT id + 1 FROM a WHERE id < 100), -- range 1..100
b AS (SELECT id FROM my_table) -- your table ID list
SELECT a.id -- find numbers from the range that do not exist in main table
FROM a
LEFT JOIN b ON b.id = a.id
WHERE b.id IS NULL
-- LIMIT 1 -- uncomment if only the first value is needed
person
AlexM
schedule
10.08.2016
Моя догадка:
SELECT MIN(p1.field) + 1 as gap
FROM table1 AS p1
INNER JOIN table1 as p3 ON (p1.field = p3.field + 2)
LEFT OUTER JOIN table1 AS p2 ON (p1.field = p2.field + 1)
WHERE p2.field is null;
person
Leonel Martins
schedule
21.08.2009
Я написал быстрый способ сделать это. Не уверен, что это самый эффективный вариант, но выполняет свою работу. Обратите внимание, что он не сообщает вам пробел, но сообщает идентификатор до и после пробела (имейте в виду, что пробел может быть несколькими значениями, например 1,2,4,7,11 и т. Д.)
Я использую sqlite в качестве примера
Если это ваша структура таблицы
create table sequential(id int not null, name varchar(10) null);
и это твои ряды
id|name
1|one
2|two
4|four
5|five
9|nine
Запрос
select a.* from sequential a left join sequential b on a.id = b.id + 1 where b.id is null and a.id <> (select min(id) from sequential)
union
select a.* from sequential a left join sequential b on a.id = b.id - 1 where b.id is null and a.id <> (select max(id) from sequential);
https://gist.github.com/wkimeria/7787ffe84d1c54216f1b320996b17b7e
person
William Kimeria
schedule
25.03.2019
Вот стандартное решение SQL, которое работает на всех серверах баз данных без изменений:
select min(counter + 1) FIRST_GAP
from my_table a
where not exists (select 'x' from my_table b where b.counter = a.counter + 1)
and a.counter <> (select max(c.counter) from my_table c);
Смотрите в действии для;
- PL / SQL через Oracle lifeql,
- MySQL через sqlfiddle,
- PostgreSQL через sqlfiddle
- MS Sql через sqlfiddle
person
Mehmet Kaplan
schedule
14.07.2017
Это работает также для пустых таблиц или с отрицательными значениями. Только что протестировано в SQL Server 2012
select min(n) from (
select case when lead(i,1,0) over(order by i)>i+1 then i+1 else null end n from MyTable) w
person
Horaciux
schedule
15.07.2017
Если вы используете Firebird 3, это будет наиболее элегантно и просто:
select RowID
from (
select `ID_Column`, Row_Number() over(order by `ID_Column`) as RowID
from `Your_Table`
order by `ID_Column`)
where `ID_Column` <> RowID
rows 1
person
Rosen Nikolov
schedule
15.11.2017
Было обнаружено, что большинство подходов выполняются очень, очень медленно в mysql
. Вот мое решение для mysql < 8.0
. Проверено на 1 млн записей с разрывом в конце ~ 1 секунда до конца. Не уверен, подходит ли он другим вариантам SQL.
SELECT cardNumber - 1
FROM
(SELECT @row_number := 0) as t,
(
SELECT (@row_number:[email protected]_number+1), cardNumber, [email protected]_number AS diff
FROM cards
ORDER BY cardNumber
) as x
WHERE diff >= 1
LIMIT 0,1
I assume that sequence starts from `1`.
person
Max Ivanov
schedule
10.01.2019
Если ваш счетчик начинается с 1 и вы хотите сгенерировать первый номер последовательности (1), когда он пуст, вот исправленный фрагмент кода из первого ответа, действительного для Oracle:
SELECT
NVL(MIN(id + 1),1) AS gap
FROM
mytable mo
WHERE 1=1
AND NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
AND EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = 1
)
person
kozo
schedule
15.03.2019
Если числа в столбце являются положительными целыми числами (начиная с 1), то вот как легко решить эту проблему. (при условии, что ID – это имя вашего столбца)
SELECT TEMP.ID
FROM (SELECT ROW_NUMBER() OVER () AS NUM FROM 'TABLE-NAME') AS TEMP
WHERE ID NOT IN (SELECT ID FROM 'TABLE-NAME')
ORDER BY 1 ASC LIMIT 1
person
Abrhalei
schedule
11.10.2019
Вот альтернатива, чтобы показать диапазон всех возможных значений зазора портативным и более компактным способом:
Предположим, ваша схема таблицы выглядит так:
> SELECT id FROM your_table;
+-----+
| id |
+-----+
| 90 |
| 103 |
| 104 |
| 118 |
| 119 |
| 120 |
| 121 |
| 161 |
| 162 |
| 163 |
| 185 |
+-----+
Чтобы получить диапазоны всех возможных значений зазора, у вас есть следующий запрос:
- В подзапросе перечисляются пары идентификаторов, в каждой из которых столбец
lowerbound
меньше столбцаupperbound
, затем используютсяGROUP BY
иMIN(m2.id)
, чтобы уменьшить количество бесполезных записей. - Внешний запрос дополнительно удаляет записи, в которых
lowerbound
равноupperbound - 1
. - Мой запрос (явно) не выводит 2 записи
(YOUR_MIN_ID_VALUE, 89)
и(186, YOUR_MAX_ID_VALUE)
на обоих концах, что неявно означает, что любое число в обоих диапазонах до сих пор не использовалось вyour_table
.
> SELECT m3.lowerbound + 1, m3.upperbound - 1 FROM
(
SELECT m1.id as lowerbound, MIN(m2.id) as upperbound FROM
your_table m1 INNER JOIN your_table
AS m2 ON m1.id < m2.id GROUP BY m1.id
)
m3 WHERE m3.lowerbound < m3.upperbound - 1;
+-------------------+-------------------+
| m3.lowerbound + 1 | m3.upperbound - 1 |
+-------------------+-------------------+
| 91 | 102 |
| 105 | 117 |
| 122 | 160 |
| 164 | 184 |
+-------------------+-------------------+
person
Han
schedule
17.03.2021
Вы можете попробовать следующее:
select *
from yourtable
where ltrim(rtrim(yourcolumn)) = ''
Идея состоит в том, что если обрезка значения оставляет вас пустой строкой, то все, что у вас было в первую очередь, было пробелом.
Вы также можете просто сделать это:
select *
from yourtable
where yourcolumn like ' '
Обратите внимание, что я проверил второй запрос на SQL Server 2008 R2, и он не работает в 2014 году, как указано в комментариях @gunr2171
Наконец, если у вас есть вкладка, возврат каретки или фид строки, вышеуказанное не будет работать. Что вы можете сделать, так это сначала заменить эти значения пустой строкой, а затем использовать первый запрос следующим образом:
select *
from yourtable
where ltrim(rtrim(replace(replace(replace(yourcolumn,char(9),''),char(10),''),char(13),''))) = ''
char(9)
, char(10)
и char(13)
используются для отображения табуляции, строки и возврата каретки соответственно.