MySQL - сложный запрос, включающий столбцы поиска из нескольких таблиц - PullRequest
0 голосов
/ 23 января 2011

Здесь мы идем снова ...

[EDIT] Внизу есть обновление с SQL для создания тестовой базы данных.[EDIT]

Я несколько дней боролся с довольно сложным для меня SQL-запросом.Я бы никогда не продвинулся так далеко без всей огромной помощи со стороны SO, которая научила меня большому количеству SQL.

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

Фон

У меня есть одна таблица с целочисленными атрибутами (IntegerAttributes).Идентификатор представляет собой идентификатор элемента, где ключ представляет собой имя атрибута, прикрепленного к элементу с идентификатором «ID», а значение представляет собой значение атрибута и может быть только целым числом.Один элемент может иметь от 0 до многих атрибутов.

IntegerAttributes
ID  Key       Value
1   Location  3
1   Color     5
2   Location  1
3   Color     3

Значением атрибута «Местоположение» является идентификатор в другой таблице под названием «Местоположения»

Locations
ID Location etc...
1  Boston
2  Manilla
3  Stockholm
4  Beijing

Значение атрибута«Цвет» - это идентификатор в другой таблице с именем «Цвета»

Locations
ID Color
1  Blue
2  Black
3  White
4  Red
5  Green

. Существует также аналогичная таблица для строк (StringAttributes), которая работает так же, как IntegerAttributes, за исключением того, что столбец «Значение» - это текст.И IntegerAttributes, и StringAttributes объединяются и преобразуются в строки с помощью UNION ALL.

На этом этапе таблица, содержащая каждый элемент, очень проста:

ID  Checkin
1   2010-01-22 11:28:18
2   2010-01-21 16:27:54
3   2010-01-20 18:40:07

Пока все понятно, но теперьэто усложняется:

Это SQL-запрос, который я использую для извлечения всех атрибутов и объединения их в строку JSON и извлечения данных элемента

SELECT
  i.ID,
  i.Checkin,
  CONCAT('{\"Date\":\"',i.Checkin,'\",', GROUP_CONCAT('\"',Attribute.key, '\":\"', CONVERT(Attribute.value,CHAR), '\"'), '}') as Attributes
  # , l.Location
FROM  (
  SELECT ItemID, ats.Key, ats.Value
  FROM attributeStrings as ats 
  UNION ALL
  SELECT ItemID, ati.Key, ati.Value
  FROM attributeIntegers as ati
) Attribute
JOIN Items i ON i.ID = Attribute.ItemID
  # JOIN locations l ON (Attribute.Key = 'Location' AND l.ID = Attribute.Value)
GROUP BY ItemID
ORDER BY i.ID DESC

Как видите, я отметил двая вернусь к ним в ближайшее время.

Проблема

Результат запроса выше будет примерно таким:

ID  Checkin              Attributes
1   2010-01-22 11:28:18  {"Date":"2010-01-22 11:28:18","Location":"3","Color":"5"}
2   2010-01-21 16:27:54  {"Date":"2010-01-21 16:27:54","Location":"1"}
3   2010-01-20 18:40:07  {"Date":"2010-01-20 18:40:07","Color":"3"}

Пока все хорошо.

Но теперь я хотел бы включить поиск в «Location» (и, в конце концов, в «Color» или другие атрибуты с идентификатором lookup-ID).

Если я раскомментирую две строки взапрос выше

# , l.Location
# JOIN locations l ON (Attribute.Key = 'Location' AND l.ID = Attribute.Value)

Я получаю результаты только в том случае, если единственным атрибутом является «Местоположение», а поле «Атрибуты» теперь будет содержать только атрибуты «Дата» и «Местоположение».

ID  Checkin              Attributes                                     Location
2   2010-01-21 16:27:54  {"Date":"2010-01-21 16:27:54","Location":"1"}  Boston

Желаемое резюмеlt

Результат, который я хочу получить, такой же, как и раньше, но с дополнительным столбцом с атрибутом «Местоположение» (а затем и с другими столбцами поиска), который был найден в Locations.хочу:

ID  Checkin              Attributes                                                 Location   Color
1   2010-01-22 11:28:18  {"Date":"2010-01-22 11:28:18","Location":"3","Color":"5"}  Stockholm  Green
2   2010-01-21 16:27:54  {"Date":"2010-01-21 16:27:54","Location":"1"}              Boston     null
3   2010-01-20 18:40:07  {"Date":"2010-01-20 18:40:07","Color":"3"}                 null       White

Спасибо, что прочитали все здесь: D Я пытался уточнить с IF EXISTS, но я не могу понять, как это сделать.

[РЕДАКТИРОВАТЬ] SQL ДЛЯ СОЗДАНИЯ ИСПЫТАТЕЛЬНОЙ БАЗЫ ДАННЫХ [РЕДАКТИРОВАТЬ]

-- MySQL Administrator dump 1.4
--
-- ------------------------------------------------------
-- Server version   5.1.47-community


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


--
-- Create schema swebussandbox
--

CREATE DATABASE IF NOT EXISTS SODatabase;
USE SODatabase;

--
-- Definition of table `attributeintegers`
--

DROP TABLE IF EXISTS `attributeintegers`;
CREATE TABLE `attributeintegers` (
  `ItemID` int(10) unsigned NOT NULL,
  `Key` varchar(45) NOT NULL,
  `Value` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`ItemID`,`Key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

--
-- Dumping data for table `attributeintegers`
--

/*!40000 ALTER TABLE `attributeintegers` DISABLE KEYS */;
INSERT INTO `attributeintegers` (`ItemID`,`Key`,`Value`) VALUES
 (4,'Color',17),
 (4,'Location',3),
 (5,'Location',2),
 (6,'Location',6),
 (7,'Color',15),
 (8,'Location',8),
 (9,'Location',10),
 (10,'Color',15),
 (10,'Location',2),
 (11,'Color',15),
 (11,'Location',4),
 (12,'Color',15),
 (12,'Location',3),
 (13,'Color',15),
 (13,'Location',8),
 (14,'Location',3),
 (15,'Location',6),
 (16,'Color',18),
 (18,'Color',15),
 (18,'Location',4);
 /*!40000 ALTER TABLE `attributeintegers` ENABLE KEYS */;


--
-- Definition of table `attributestrings`
--

DROP TABLE IF EXISTS `attributestrings`;
CREATE TABLE `attributestrings` (
  `ItemID` int(10) unsigned NOT NULL DEFAULT '0',
  `Key` varchar(45) NOT NULL DEFAULT '_NA_',
  `Value` text,
  PRIMARY KEY (`ItemID`,`Key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

--
-- Dumping data for table `attributestrings`
--

/*!40000 ALTER TABLE `attributestrings` DISABLE KEYS */;
INSERT INTO `attributestrings` (`ItemID`,`Key`,`Value`) VALUES
 (5,'Type','BagForm'),
 (6,'Type','BagForm'),
 (9,'Type','BagForm'),
 (10,'Type','BagForm'),
 (11,'Type','BagForm'),
 (12,'Brand','Bogcase'),
 (12,'Type','BagForm'),
 (14,'Type','BagForm'),
 (15,'Brand','Carryline World Wide'),
 (15,'Type','BagForm'),
 (16,'Brand','Fjällräven'),
 (16,'Type','BagForm'),
 (17,'Brand','Packard Bell'),
 (17,'Tech','ComputerForm'),
 (17,'Type','TechGUI');
/*!40000 ALTER TABLE `attributestrings` ENABLE KEYS */;



--
-- Definition of table `colors`
--

DROP TABLE IF EXISTS `colors`;
CREATE TABLE `colors` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Color` varchar(45) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `colors`
--

/*!40000 ALTER TABLE `colors` DISABLE KEYS */;
INSERT INTO `colors` (`ID`,`Color`) VALUES
 (1,'Multicolored'),
 (2,'Black'),
 (3,'White'),
 (4,'Red'),
 (5,'Green'),
 (6,'Blue'),
 (7,'Yellow'),
 (8,'Black'),
 (9,'Gold'),
 (10,'Bown'),
 (11,'Purpul'),
 (12,'Pink'),
 (13,'Orange'),
 (14,'Gray'),
 (15,'Transparent');
/*!40000 ALTER TABLE `colors` ENABLE KEYS */;



--
-- Definition of table `items`
--

DROP TABLE IF EXISTS `items`;
CREATE TABLE `items` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `CheckIn` datetime DEFAULT NULL,
  `Line` int(10) unsigned DEFAULT NULL,
  `TypeID` int(10) unsigned DEFAULT NULL,
  `SizeID` int(10) unsigned DEFAULT NULL,
  `ColorID` int(10) unsigned DEFAULT NULL,
  `MaterialID` int(10) unsigned DEFAULT NULL,
  `CheckOut` datetime DEFAULT NULL,
  `LocationID` int(10) unsigned DEFAULT NULL,
  `Notes` text,
  `Tur` int(10) unsigned DEFAULT NULL,
  `Bus` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`ID`),
  FULLTEXT KEY `NoteIndex` (`Notes`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 PACK_KEYS=1;

--
-- Dumping data for table `items`
--

/*!40000 ALTER TABLE `items` DISABLE KEYS */;
INSERT INTO `items` (`ID`,`CheckIn`) VALUES
 (4,'2010-12-03 02:04:38'),
 (5,'2010-12-27 02:11:25'),
 (6,'2010-12-27 02:14:28'),
 (7,'2010-12-25 02:17:09'),
 (8,'2010-12-24 02:33:49'),
 (9,'2011-01-06 07:48:16'),
 (10,'2011-01-06 07:47:09'),
 (11,'2010-12-31 10:53:26');
/*!40000 ALTER TABLE `items` ENABLE KEYS */;


--
-- Definition of table `locations`
--

DROP TABLE IF EXISTS `locations`;
CREATE TABLE `locations` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Location` varchar(45) NOT NULL,
  `Group` int(10) unsigned NOT NULL DEFAULT '1',
  `Address` text,
  `Phone` varchar(20) DEFAULT NULL,
  `Contact` varchar(45) DEFAULT NULL,
  `Hours` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `locations`
--

/*!40000 ALTER TABLE `locations` DISABLE KEYS */;
INSERT INTO `locations` (`ID`,`Location`) VALUES
 (1,'Boston'),
 (2,'Stockholm'),
 (3,'Manilla'),
 (4,'Berlin'),
 (5,'Oslo'),
 (6,'Paris'),
 (7,'London'),
 (8,'Amsterdam'),
 (9,'Helsinki'),
 (10,'Kopenhagen'),
 (11,'Barselona'),
 (12,'Luxenbourg'),
 (13,'Milano');
/*!40000 ALTER TABLE `locations` ENABLE KEYS */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

Я опробовал предложение от Тумблер с этим обновленным запросом:

SELECT
  i.ID,
  i.Checkin,
  CONCAT('{\"Date\":\"',i.Checkin,'\",', GROUP_CONCAT('\"',Attribute.key, '\":\"', CONVERT(Attribute.value,CHAR), '\"'), '}') as Attributes,
  COALESCE(l.Location,null) as Location,
  COALESCE(c.Color,null) as Color
FROM  (
  SELECT ItemID, ats.Key, ats.Value
  FROM attributeStrings as ats
  UNION ALL
  SELECT ItemID, ati.Key, ati.Value
  FROM attributeIntegers as ati
) Attribute
LEFT JOIN locations l ON (Attribute.Key = 'Location' AND l.ID = Attribute.Value)
LEFT JOIN Colors c ON (Attribute.Key = 'Color' AND c.ID = Attribute.Value)
JOIN Items i ON i.ID = Attribute.ItemID
GROUP BY ItemID
ORDER BY i.ID DESC

... но он отображает все атрибуты, но только для элементов, которые имеют местоположение или цвет в качестве атрибута ONLY.

Ответы [ 2 ]

2 голосов
/ 23 января 2011

Попробуйте левое соединение

LEFT JOIN locations l ON (Attribute.Key = 'Location' AND l.ID = Attribute.Value)

И если пустые значения являются проблемой:

, COALESCE(l.Location,'No Location')

Ваш пример слишком сложен, чтобы его можно было легко воспроизвести, но дайте нам знать, как он работает.

1 голос
/ 24 января 2011
SELECT  i.ID, i.checkin,
        CONCAT('{\"Date\":\"', i.checkin,'\",', GROUP_CONCAT('\"', attribute.key, '\":\"', CONVERT(attribute.value,CHAR), '\"'), '}') as attributes,
        l.location, c.color
FROM    (
        SELECT  ItemID, ats.key, ats.value
        FROM    attributestrings as ats
        UNION ALL
        SELECT  ItemID, ati.Key, ati.Value
        FROM    attributeintegers as ati
        ) attribute
JOIN    items i
ON      i.ID = attribute.itemid
LEFT JOIN
        attributeintegers atli
ON      atli.itemid = i.id
        AND atli.key = 'Location'
LEFT JOIN
        locations l
ON      l.id = atli.value
LEFT JOIN
        attributeintegers atci
ON      atci.itemid = i.id
        AND atci.key = 'Color'
LEFT JOIN
        colors c
ON      c.id = atci.value
GROUP BY
        i.id DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...