2010-04-22 2 views
2

У меня небольшая проблемаПолучение всех строк из таблицы, где столбец содержит только 0

я нужен запрос SQL, который дает все строки обратно, которая содержит только 0 в нем.

столбец определяется как varchar2 (6) значения в столбце выглядит следующим образом:

Row  Value 
1  0 
2  00 
3  00 
4  100 
5  bc00 
6  000000 
7  00000 

мое первое решение было бы так:

Oracle: 
substr('000000' || COLUMN_NAME, -6) = '000000' 

SQL Server: 
right('000000' + COLUMN_NAME, 6) = '000000' 

есть другой способ ? (она должна работать на обеих системах)

выход будет строка 1,2,3,6,7

+0

Каков результат ваших данных образца? –

+0

выход будет строкой 1,2,3,6,7 – domiSchenk

+0

Ваше первое решение (в вашем вопросе) не будет использовать индекс, а также ваш выбранный ответ. Это означает, что вам нужно будет проверить каждую строку таблицы (сканирование таблицы), чтобы найти строки, которые вы после. Это может быть или не быть большой проблемой, зависит от того, сколько у вас строк. Если вы просто разрабатываете новое приложение и вряд ли какие-либо данные в своей таблице, то все будет быстро. Однако, когда вы добавите больше данных в таблицу, они будут медленными. Если у вас много транзакций, изменяющих эту таблицу, сканирование таблицы должно будет дождаться их завершения, прежде чем она сможет сканировать таблицу. –

ответ

3

Это самый простой:

select * from tbl where replace(col,'0','') = '' 

Если вы не будете делать вычисляемый столбец для этого выражения, вы можете выбрать для индекса функции на основе (примечание: Oracle и Postgres уже поддерживает это, Sql Server по состоянию версия 2008, еще нет), чтобы сделать это производительным:

create index ix_tbl on tbl(replace(col,'0','')) 

[EDIT]

Я просто держать ответ ниже е или потомство, я попытался объяснить, как сделать индекс использования запроса из вычисленного столбца.

Используется:

select * from tbl 
where ISNUMERIC(col) = 1 and cast(col as int) = 0 

Для ISNUMERIC нуждается в Oracle, используйте: http://www.oracle.com/technology/oramag/oracle/04-jul/o44asktom.html

[EDIT]

@Charles, повторно: вычисляемый столбец на Oracle:

Для RDBMSes, поддерживающих вычисленный столбец, но у него нет постоянной опции, да, это сделает функцию вызов для каждой строки. Если он поддерживает постоянный столбец, он не будет выполнять вызов функции, у вас есть реальный столбец в таблице, который предварительно вычисляется из этой функции. Теперь, если данные могут заставить функцию вызвать исключение, есть два сценария.

Во-первых, если вы не указали persist, это позволит вам сохранить вычисленный столбец (ALTER TABLE tbl ADD numeric_equivalent AS cast(col as int)), даже если результат данных приведет к возникновению исключения, но вы не можете безоговорочно выбрать этот столбец, это приведет к возникновению исключения :

select * from tbl 

это не поднимет исключение:

select * from tbl where is_col_numeric = 1 

это будет:

select * from tbl where numeric_equivalent = 0 and is_col_numeric = 1 

это не будет (Sql Server поддерживает short-circuiting):

select * from tbl where is_col_numeric = 1 and numeric_equivalent = 0 

Для справки, is_col_numeric выше была создана при этом:

ALTER TABLE tbl ADD 
is_col_numeric AS isnumeric(col)  

И это is_col_numeric Индекса:

create index ix_is_col_numeric on tbl(is_col_numeric) 

Теперь для второго сценария, вы помещаете вычисляемый столбец с опцией PERSISTED в таблицу, которая уже имеет существующие данные (например, «ABXY», «X1», «ETC»), который вызывает исключение, когда к нему применяется функция/выражение (например, cast), ваша RDBMS не позволит вам вывести вычисляемый столбец. Если в вашей таблице нет данных, это позволит вам установить опцию PERSISTED, но после того, как вы попытаетесь вставить данные (например, insert into tbl(col) values('ABXY')), что вызывает исключение, ваша RDBMS не позволит вам сохранять ваши данные. Таким образом, в вашей таблице может быть сохранен только числовой текст, вычисленный столбец PERSISTED дегенерируется в проверку ограничений, хотя и полностью отложенный.

Для справки, вот сохранялось вычислен образец колонки:

ALTER TABLE tbl ADD 
numeric_equivalent AS cast(col as int) persisted 

Теперь, некоторые из нас может возникнуть соблазн не ставить PERSISTED опцию на вычисляемый столбец. Это будет своего рода самоотверженный труд с точки зрения производительности, потому что вы, возможно, не сможете впоследствии создать индекс. Когда позже вы захотите создать индекс на неуправляемом вычисленном столбце, а в таблице уже есть данные «ABXY», база данных не позволит вам создать индекс. Для создания индекса необходимо получить значение из столбца, и если этот столбец вызывает исключение, он не позволит вам создавать индекс на нем.

Если мы попытаемся немного обмануть i.e, мы сразу создадим индекс на этом неуправляемом вычисленном столбце при создании таблицы, база данных позволит вам это сделать. Но когда мы вставляем «ABXY» в таблицу позже, она не будет сохранена, база данных будет автоматически создавать индексы (индексы) после того, как мы вставим данные в таблицу. Конструктор индекса получает исключение вместо данных, поэтому он не может сделать запись индекса для данных, которые мы пытались вставить, впоследствии вставка данных не произойдет.

Итак, как мы можем достичь индекса нирваны на вычисленном столбце? Прежде всего, мы убеждаемся, что вычисленный столбец PERSISTED, и это обеспечит немедленное срабатывание ошибок; если мы не поместим опцию PERSISTED, все, что может вызвать исключение, будет отложено на построение индекса, просто заставив вещи потерпеть неудачу позже. Ошибки легче найти, когда они случаются раньше. После того, как колонка сохранится, поместите на нее индекс.

Итак, если у нас есть существующие данные '00', '01', '2', это позволит нам сделать упорный вычисленный столбец.Теперь после этого, если мы вставим «ABXY», он не будет вставлен, база данных не сможет сохранить ничего из вычисленного столбца, который вызвал исключение. Таким образом, мы просто скроем собственный бросок, который не вызывает исключение.

К умственным (просто перевести это на Oracle эквивалент):

create function cast_as_int(@n varchar(20)) returns int with schemabinding 
begin 

    begin try 
     return cast(@n as int); 
    end try 
    begin catch 
     return null; 
    end catch 

end; 

Пожалуйста, к сведению, что ловить исключение в ОДС еще не будет работать в Sql Server, но Microsoft have plans to support that

Это теперь наша не -exception-поднятие сохраняется вычисляемый столбец:

ALTER TABLE tbl ADD 
numeric_equivalent AS cast_as_int(a) persisted 

Отбросьте существующий индекс, а затем воссоздать его:

create index ix_num_equiv on tbl(numeric_equivalent)  

Теперь этот запрос будет индексировать законопослушные гражданин, производительным, и не будет поднимать исключение даже порядок условий обращенное:

select * from tbl where numeric_equivalent = 0 and is_col_numeric = 1 

Чтобы сделать его более производительным, так как столбец numeric_equivalent не вызывает больше исключений, у нас нет никакой больше пользы для is_col_numeric, так что просто используйте:

select * from tbl where numeric_equivalent = 0 
+0

, который выглядит просто: D и он wokrs на обеих системах очень хороший thenk you! – domiSchenk

+0

Простой или нет, это не будет использовать индекс и принудительно сканирование таблицы.Его компромисс: простая строка кода экономит 30 секунд ввода, но приводит к тому, что никогда не используется индекс, вызывает пожизненное время медленных запросов, что избавит ресурсы от других пользователей и процессов. –

+0

Да, полностью осознавая это. поэтому я больше люблю Postgres, потому что до сих пор Sql Server по-прежнему не может поместить индекс в выражения. В Postgres вы можете поместить индекс в основном любые выражения –

0

попробовать это, который должен быть в состоянии использовать и индекс YourTable.COLUMN_NAME, если он существует:

--SQL Server syntax, but should be similar in Oracle 
--you could make this a temp of permanent table 
CREATE TABLE Zeros (Zero varchar(6)) 
INSERT INTO Zeros VALUES ('0') 
INSERT INTO Zeros VALUES ('00') 
INSERT INTO Zeros VALUES ('000') 
INSERT INTO Zeros VALUES ('0000') 
INSERT INTO Zeros VALUES ('00000') 
INSERT INTO Zeros VALUES ('000000') 

SELECT 
    y.* 
    FROM YourTable  y 
     INNER JOIN Zeros z On y.COLUMN_NAME=z.Zero 

EDIT
или даже просто так:

SELECT 
    * 
    FROM YourTable 
    WHERE COLUMN_NAME IN ('0','00','000','0000','00000','000000') 

здание от ответа Дэйва Косты:

Oracle:

SELECT 
    * 
    FROM YourTable 
    WHERE YourColumn IN 
     (SELECT LPAD('0',level,'0') FROM dual CONNECT BY LEVEL <= 6) 

SQL Server 2005 и выше:

;WITH Zeros AS 
(SELECT 
    CONVERT(varchar(6),'0') AS Zero 
UNION ALL 
SELECT '0'+CONVERT(varchar(5),Zero) 
    FROM Zeros 
    WHERE LEN(CONVERT(varchar(6),Zero))<6 
) 
select Zero from Zeros 
SELECT 
    y.* 
    FROM YourTable  y 
    WHERE y.COLUMN_NAME IN (SELECT Zero FROM Zeros) 
0

Это также будет работать в Oracle (но не в SQL Server):

REPLACE(column_name, '0') IS NULL 

Это будет работать в Oracle (и, возможно, также в SQL Server, вам нужно будет проверить):

LTRIM(column_name, '0') IS NULL 

В качестве альтернативы, так как он является (6) столбец VARCHAR, вы также можете просто проверить:

column_name IN ('0', '00', '000', '0000', '00000', '000000') 

Это не красиво, но это, вероятно, является наиболее эффективным, если существует индекс на колонка.

+0

В SQL Server LTRIM принимает только 1 параметр, а для REPLACE требуется 3 parmas. –

0

С учетом ответа KM вы можете сделать то же самое в Oracle, не создавая фактическую таблицу.

SELECT y.* 
    FROM YourTable y 
    WHERE YourColumn IN 
    (SELECT LPAD('0',level,'0') FROM dual CONNECT BY LEVEL <= 6) 

или

SELECT y.* 
    FROM YourTable y 
    INNER JOIN 
    (SELECT LPAD('0',level,'0') zeros FROM dual CONNECT BY LEVEL <= 6) z 
      ON y.YourColumn = z.zeros 

Я думаю, что это наиболее гибкий ответ, потому что, если максимальная длина изменения столбцов, вам просто нужно изменить 6 к новой длине.

+0

Угрожает, не заметил ограничения, которые вы хотите, чтобы он работал как в Oracle, так и в SQL Server. Не уверен, что SQL Server имеет аналогичную конструкцию, которая позволит вам генерировать таблицу соединений таким образом. –

+0

Слишком плохо, что нет двойной таблицы в sql, но если она должна быть одной, я могу создать один ^^ – domiSchenk

+0

SQL Server может использовать CTE для рекурсивной сборки таблиц. –

0

Как об использовании регулярных выражений (поддерживаемых оракулом, я думаю, также MSSQL)

+2

может у вас объяснить это немного больше? – domiSchenk

+0

http://www.regular-expressions.info/oracle.html Я не пробовал это, но он был подключен к wirk в ms sql также http://msdn.microsoft.com/en-us/magazine/ cc163473.aspx – zapp0

+0

с использованием регулярного выражения приведет к тому, что он не будет использовать индекс –

0

Другой SQL-версия будет:

... 
where len(COLUMN_NAME) > 0 
and len(replace(COLUMN_NAME, '0', '')) = 0 

т.е. там, где есть более чем 1 символы в столбце, и все они равны 0. Бросьте в TRIM, если могут быть ведущие, конечные или внедренные пробелы.

+0

делать это таким образом, нет изменений в использовании индекса –

2

нравится ли вам:

SELECT * FROM MY_TABLE 
WHERE REPLACE (MY_COLUMN, '0', NULL) IS NULL 
AND MY_COLUMN IS NOT NULL; 
+1

+1 И элегантный, и дешевый. –

+1

К сожалению, это не работает, но я не буду его понижать. просто измените это на: 'select * from tbl где replace (col, '0', '') = ''' –

+0

Майкл, что заставляет вас сказать, что он не работает? Я тестировал его, и это работало для меня. –

Смежные вопросы