Выбор записи на основе целого числа, находящегося в поле массива - PullRequest
0 голосов
/ 06 февраля 2011

У меня есть база домов. В базе данных записей базы данных mssql есть поле под названием areaID. Дом может находиться в нескольких областях, поэтому запись в базе данных может выглядеть следующим образом:

+---------+----------------------+-----------+-------------+-------+
| HouseID | AreaID               | HouseType | Description | Title |
+---------+----------------------+-----------+-------------+-------+
| 21      | 17, 32, 53           | B         | data        | data  |
+---------+----------------------+-----------+-------------+-------+
| 23      | 23, 73               | B         | data        | data  |
+---------+----------------------+-----------+-------------+-------+
| 24      | 53, 12, 153, 72, 153 | B         | data        | data  |
+---------+----------------------+-----------+-------------+-------+
| 23      | 23, 53               | B         | data        | data  |
+---------+----------------------+-----------+-------------+-------+

Если бы я открыл страницу, в которой требовались дома только в районе 53, как бы я ее нашел? Я знаю, что в MySQL вы можете использовать find_in_SET, но я использую Microsoft SQL Server 2005.

Ответы [ 4 ]

5 голосов
/ 06 февраля 2011

Если ваше форматирование ТОЧНО

N1, N2 (e.g.) one comma and space between each N

Тогда используйте это предложение WHERE

WHERE ', ' + AreaID + ',' LIKE '%, 53,%'

Добавление префикса и суффикса делает каждое число в любом месте списка последовательно заключенным в запятую и суффиксом через запятую. В противном случае вы можете получить ложные срабатывания, если 53 появятся в виде части другого номера.

Примечание

  1. Выражение LIKE будет совсем не быстрым, поскольку оно всегда будет сканировать всю таблицу.
  2. Вы должны рассмотреть вопрос о нормализации данных в две таблицы:

Столы становятся

House
+---------+----------------------+----------+
| HouseID | HouseType | Description | Title |
+---------+----------------------+----------+
| 21      | B         | data        | data  |
| 23      | B         | data        | data  |
| 24      | B         | data        | data  |
| 23      | B         | data        | data  |
+---------+----------------------+----------+

HouseArea
+---------+-------
| HouseID | AreaID
+---------+-------
| 21      | 17
| 21      | 32
| 21      | 53
| 23      | 23
| 23      | 73
..etc

Тогда вы можете использовать

select * from house h
where exists (
    select *
    from housearea a
    where h.houseid=a.houseid and a.areaid=53)
0 голосов
/ 06 февраля 2011

Используйте функцию Split для преобразования значений, разделенных запятыми, в строки.

CREATE TABLE Areas (AreaID int PRIMARY KEY);
CREATE TABLE Houses (HouseID int PRIMARY KEY, AreaIDList varchar(max));
GO

INSERT INTO Areas VALUES (84);
INSERT INTO Areas VALUES (24);
INSERT INTO Areas VALUES (66);
INSERT INTO Houses VALUES (1, '84,24,66');
INSERT INTO Houses VALUES (2, '24');
GO

CREATE FUNCTION dbo.Split (@values varchar(512)) RETURNS table
AS
RETURN
    WITH Items (Num, Start, [Stop]) AS (
      SELECT 1, 1, CHARINDEX(',', @values)
      UNION ALL
      SELECT Num + 1, [Stop] + 1, CHARINDEX(',', @values, [Stop] + 1)
      FROM Items
      WHERE [Stop] > 0
    )
    SELECT Num, SUBSTRING(@values, Start, 
        CASE WHEN [Stop] > 0 THEN [Stop] - Start ELSE LEN(@values) END) Value
    FROM Items;
GO

CREATE VIEW dbo.HouseAreas
AS
    SELECT h.HouseID, s.Num HouseAreaNum,
        CASE WHEN s.Value NOT LIKE '%[^0-9]%'
               THEN CAST(s.Value AS int)
            END AreaID
    FROM Houses h
    CROSS APPLY dbo.Split(h.AreaIDList) s
GO

SELECT DISTINCT h.HouseID, ha.AreaID
FROM Houses h
INNER JOIN HouseAreas ha ON ha.HouseID = h.HouseID
WHERE ha.AreaID = 24
0 голосов
/ 06 февраля 2011

Что такое тип данных AreaID?

Если это поле text , вы можете что-то вроде

WHERE ( 
         AreaID LIKE '53,%'     -- Covers: multi number seq w/ 53 at beginning  
      OR AreaID LIKE '% 53,%'   -- Covers: multi number seq w/ 53 in middle
      OR AreaID LIKE '% 53'     -- Covers: multi number seq w/ 53 at end
      OR AreaID = '53'          -- Covers: single number seq w/ only 53
      )

Примечание: я некоторое время не использовал SQL-сервер, поэтому не уверен насчет операторов. PostgreSQL имеет функцию регулярного выражения, которая была бы лучше при сжатии этого оператора WHERE. Кроме того, я не уверен, что приведенный выше пример будет включать числа, такие как 253 или 531; это не должно, но вам все равно нужно проверить.

Кроме того, есть множество функций, которые перебирают массивы, поэтому лучше хранить их как массив против текста. Наконец, это может быть хорошим примером использования хранимой процедуры, так что вы можете вызывать свою самодельную функцию вместо того, чтобы загромождать свой SQL.

0 голосов
/ 06 февраля 2011

2, измените идентификаторы AreaId, чтобы вы могли использовать оператор & ИЛИ создать таблицу, которая связывает дом и район ....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...