SQL Select语句中的动态列,保持"未定义"值

时间:2017-04-29 12:04:06

标签: mysql sql select mariadb

这是一个基于我的热门问题的新问题,该问题被标记为“重复”问题。这个问题 mySQL - Create a New Table Using Data and Columns from Three Tables

这个问题看起来很相似,但有一个不同的重要部分 我试图使用链接的解决方案,但Ansers不适合我的问题。

我的个人SQL技能有限。环顾四天后,我没有找到任何有效的解决方案来解决我的数据库查询问题。我在这个问题的最后附上了完整的示例数据库SQL文本。 我的示例数据库(使用MariaDB制作)包含两个表:

  • 项目和
  • itemproperties。

对于每件商品,仅定义 item.ID item.Name 。 (在现实生活中的例子中,名称将被定义为唯一的。)

对于每个项目,都可以使用动态用户定义的属性集。这些属性定义为名称 - 值对。 例如,对于名为" Banana "的项目属性" 颜色"价值" 黄色"可能存在。

只有一个"颜色"才有效。一个项目的属性,因此不能将两种不同的颜色分配给一个项目。

(在我的实际问题中,属性名称只包含两个字符,因此不需要额外的属性名称表,以及随后为了便于显示示例中未使用的问题)。

items表的示例数据:

ID, Name
1,  Car
2,  House
3,  Homer
4,  Earth

定义了上述项目的总共九个属性。条目"(NULL)"表示未为给定项目定义此属性

ItemID, ItemName, Color,    Speed,  Price
1,      Car,      blue,       200,  50000
2,      House,    red,     (NULL), 250000
3,      Homer,    yellow,       5, (NULL)
4,      Earth,    blue,    108000, (NULL)

不幸的是我的选择陈述

SELECT items.ID as ItemID, items.Name as ItemName,
CASE WHEN (itemproperties.Name = 'Color')
       THEN itemproperties.Value
       #ELSE NULL
END as Color,
CASE WHEN (itemproperties.Name = 'Speed')
       THEN itemproperties.Value
       #ELSE NULL
END as Speed,
CASE WHEN (itemproperties.Name = 'Price')
       THEN itemproperties.Value
       #ELSE NULL
END as Price
FROM items left join itemproperties 
ON  (items.ID=itemproperties.ItemID)

返回这样的数据

ItemID, ItemName, Color,   Speed, Price
1,      Car,      blue,   (NULL), (NULL)
1,      Car,      (NULL),  200,   (NULL)
1,      Car,      (NULL), (NULL), 50000
2,      House,    red,    (NULL), (NULL)
2,      House,    (NULL), (NULL), 250000
3,      Homer,    yellow, (NULL), (NULL)
3,      Homer,    (NULL),      5, (NULL)
4,      Earth,    blue,   (NULL), (NULL)
4,      Earth,    (NULL), 108000, (NULL)

问题:如何编写select语句以整理形式获取数据,每个项目一行?

根据上面的链接问题,我也尝试了以下方法

SELECT i.ID as ItemID, i.Name as ItemName, 
       p1.Value AS Color, p2.Value AS Speed, p3.Value AS Price
FROM items as i
JOIN itemproperties AS p1 ON (i.ID=p1.ItemID)
JOIN itemproperties AS p2 ON (i.ID=p2.ItemID)
JOIN itemproperties AS p3 ON (i.ID=p3.ItemID)
WHERE (p1.Name = 'Color') and (p2.Name = 'Speed') and (p3.Name = 'Price')

但结果只有一行:

ItemID, ItemName, Color, Speed, Price
1,      Car,      blue,    200, 50000

这种行为的原因是,该项目是" Car"拥有所有三个属性" Color"," Speed"和"价格"充满价值。 项目" House"被跳过,因为它有一个"颜色"和#34; Price",但显然没有" Speed"。

那么如何以理想的方式获取表格呢?

问候Ekkehard

数据库定义:

-- --------------------------------------------------------
-- Host:                         127.0.0.1
-- Server Version:               10.1.13-MariaDB - mariadb.org binary distribution
-- Server Betriebssystem:        Win32
-- HeidiSQL Version:             9.4.0.5125
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!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' */;


-- Exportiere Datenbank Struktur für DynamicColTest
CREATE DATABASE IF NOT EXISTS `dynamiccoltest` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `DynamicColTest`;

-- Exportiere Struktur von Tabelle DynamicColTest.itemproperties
CREATE TABLE IF NOT EXISTS `itemproperties` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique ID of the property',
  `ItemID` int(10) unsigned DEFAULT '0' COMMENT 'ID of the Item this property belongs to',
  `Name` varchar(20) DEFAULT '0' COMMENT 'Name of the property',
  `Value` varchar(20) DEFAULT '0' COMMENT 'Value of the property',
  UNIQUE KEY `Schlüssel 3` (`Name`,`ItemID`),
  KEY `Schlüssel 1` (`ID`),
  KEY `FK_itemproperties_items` (`ItemID`),
  CONSTRAINT `FK_itemproperties_items` FOREIGN KEY (`ItemID`) REFERENCES `items` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COMMENT='The properties of the items';

-- Exportiere Daten aus Tabelle DynamicColTest.itemproperties: ~9 rows (ungefähr)
DELETE FROM `itemproperties`;
/*!40000 ALTER TABLE `itemproperties` DISABLE KEYS */;
INSERT INTO `itemproperties` (`ID`, `ItemID`, `Name`, `Value`) VALUES
    (1, 1, 'Color', 'blue'),
    (1, 4, 'Color', 'blue'),
    (1, 2, 'Color', 'red'),
    (2, 3, 'Color', 'yellow'),
    (3, 1, 'Speed', '200'),
    (3, 4, 'Speed', '108000'),
    (4, 3, 'Speed', '5'),
    (5, 1, 'Price', '50000'),
    (5, 2, 'Price', '250000');
/*!40000 ALTER TABLE `itemproperties` ENABLE KEYS */;

-- Exportiere Struktur von Tabelle DynamicColTest.items
CREATE TABLE IF NOT EXISTS `items` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique Item ID',
  `Name` varchar(25) DEFAULT '0' COMMENT 'Name of the Item',
  KEY `Schlüssel 1` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 COMMENT='Contains all Items, with a minimum of definitions';

-- Exportiere Daten aus Tabelle DynamicColTest.items: ~4 rows (ungefähr)
DELETE FROM `items`;
/*!40000 ALTER TABLE `items` DISABLE KEYS */;
INSERT INTO `items` (`ID`, `Name`) VALUES
    (1, 'Car'),
    (2, 'House'),
    (3, 'Homer'),
    (4, 'Earth');
/*!40000 ALTER TABLE `items` ENABLE KEYS */;

/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

2 个答案:

答案 0 :(得分:1)

你非常接近。您需要为需要检索的每个不同密钥(属性)加入一次键/值表itemproperties。问题是,您需要使用LEFT JOIN。当连接标准未满足时,普通内部JOIN会抑制输出行。

试试这个。

SELECT i.ID as ItemID, i.Name as ItemName, 
       p1.Value AS Color, p2.Value AS Speed, p3.Value AS Price
  FROM items as i
  LEFT JOIN itemproperties AS p1 ON (i.ID=p1.ItemID) AND (p1.Name = 'Color')
  LEFT JOIN itemproperties AS p2 ON (i.ID=p2.ItemID) AND (p2.Name = 'Speed')
  LEFT JOIN itemproperties AS p3 ON (i.ID=p3.ItemID) AND (p3.Name = 'Price')

选择Name值(z.B。p3.Name = 'Price')的表达式会出现在ON子句中,而不是WHERE子句中。

答案 1 :(得分:0)

以下答案适用于SQL SERVER,但我希望它对您有所帮助。我正在使用PIVOT函数来实现结果。您尤其可以使用类似函数in MariaDB

WITH cte as(   
SELECT i.ID as ItemID, i.Name as ItemName,p1.name,p1.value
FROM items as i
JOIN itemproperties AS p1 ON (i.ID=p1.ItemID)
)

select * from cte
PIVOT
(
    max(value) for Name in ([Color],[Speed],[Price])
)A

REXTESTER DEMO