Sql как найти пробел

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's user avatar

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

Iain Samuel McLean Elder's user avatar

answered Jul 25, 2009 at 2:41

Joe's user avatar

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 Sansom's user avatar

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-K's user avatar

A-KA-K

16.7k8 gold badges53 silver badges71 bronze badges

1

The following worked for me:

PrdPicture LIKE '%'+char(160)+'%'

Martin Evans's user avatar

Martin Evans

45.4k17 gold badges79 silver badges94 bronze badges

answered Jul 6, 2017 at 6:23

Pratheeskumar's user avatar

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's user avatar

FallenAngel

18k15 gold badges82 silver badges113 bronze badges

answered Jul 25, 2009 at 9:03

gbn's user avatar

gbngbn

420k81 gold badges584 silver badges674 bronze badges

0

Use below query:

SELECT UniqueName 
FROM employee
WHERE employeeName LIKE '% %'

Prashant Pimpale's user avatar

answered Aug 23, 2018 at 15:53

pradeep's user avatar

select * from [sometable] where somecolumn like '% %'

FallenAngel's user avatar

FallenAngel

18k15 gold badges82 silver badges113 bronze badges

answered Jul 25, 2009 at 2:24

KellCOMnet's user avatar

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

Xanderak's user avatar

Как узнать есть ли пробелы в строке данных или строке запроса клиента через 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

Скриншоты:

TRUE - Пробелы есть в строке данных - PostgreSQL

TRUE — Пробелы есть в строке данных — PostgreSQL
FALSE - Пробелов нет в строке данных - PostgreSQL
FALSE — Пробелов нет в строке данных — PostgreSQL

Как удалить эту функцию?

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) используются для отображения табуляции, строки и возврата каретки соответственно.

Добавить комментарий