Требуется сложный SQL-запрос, поиск суммы подзапроса - PullRequest
2 голосов
/ 19 апреля 2019

Соответствующая часть моей базы данных выглядит следующим образом (MS Visio, я знаю, что я жалок: D): Description?

Мне нужно извлечь список, состоящий из всех элементов в категории, а также связок. Поэтому я должен использовать UNION. Первая часть UNION для вашей справки (поскольку она устанавливает формат данных для SELECT во второй части UNION; обратите внимание, что ? указывает, куда входит аргумент node-mysql):

SELECT `ID`, `Name`, `Description`, 
       `PictureID`, `SellingPrice`,
       `Cost`, 0 AS `Bundle` 
FROM `Item` 
WHERE `CategoryID`=? AND 
`ID` IN ( 
         SELECT `ItemID` 
         FROM `Stock` 
         WHERE `CityID`=? 
         AND `IsLimitless`=1 OR `Quantity`>0
        ) 

Итак, я хочу представить свои Пакеты, как если бы они были также элементами, с одинаковыми полями и т. Д.

Моя попытка:

SELECT `ID`, `Name`, `Description`, `PictureID`, 
      (
       SELECT SUM( // Here SQL indicates a syntax problem
                  SELECT `ItemAmount`*`PriceModifier`*(
                                         SELECT `SellingPrice` 
                                         FROM `Item` 
                                         WHERE `ID`=`BundleItem`.`ItemID`
                                         ) 
                   FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
                 )
      ) AS `SellingPrice`,
      (
        SELECT SUM(
                   SELECT `ItemAmount`*(
                                        SELECT `Cost` 
                                        FROM `Item` 
                                        WHERE `ID`=`BundleItem`.`ItemID`
                                       )
                    FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
                  )
      ) AS `Cost`, 
      1 AS `Bundle`
FROM `Bundle` 
WHERE `ID` IN (
               SELECT `BundleID` 
               FROM `BundleCategory` 
               WHERE `CategoryID`=?
              )
//No need to check bundles for stock due to business logic

У меня есть слабая идея, что я слишком усложняю это, но, к сожалению, я не могу это понять.

Любой совет будет очень кстати, и заранее спасибо, что нашли время. <3 </p>

Пример данных:

Fields of no interest like "Description"/"PictureID"/"SupplierID" will be omitted
for the relevant parts to fit on screen

**Bundle**
ID  Name            Description             PictureID
1   Valentine Pack  Blah-blah tasty buy me  imgur link in text

**Item**
ID  Name               SellingPrice  Cost  CategoryID
1   Movie Ticket       10            2     24
2   Box of Chocolates  5             1     4
3   Teddy Bear         15            3     2
4   Roses              10            4     8

**Stock**
ItemID  CityID  Quantity  IsLimitLess 
1       1       25        false
1       2       11        false
2       1       84        false
3       1       33        false
4       1       1         true
4       3       1         true

**BundleItem**
BundleID  ItemID  ItemAmount  PriceModifier
1         1       2           1.25
1         2       1           1
1         3       1           1
1         4       5           0.75

**BundleCategory** (bundle for marketing reasons can appear in different
categories depending on its contents)
BundleID  CategoryID
1         4 //Sweets
1         2 //Toys
1         8 //Flowers

Желаемый вывод: (Для поиска CityID 1, CategoryID 8, Flowers)

ID  Name    (Descr/PicID)    SellingPrice Cost         Bundle

4   Roses                    10           4            false

1   Valentine Pack           82.5         28           true
                           /*2*10*1.25+   2*2+  <movie
                             1*1*5+       1*1+  <chocolate
                             1*1*15+      3*1+  <teddy bear
                             5*0.75*10    5*4   <roses */

Предлагаемые пользователем решения По предложению @ drakin8564 я попытался сделать

SELECT `ID`, `Name`, `Description`, `PictureID`, 
      (
       SELECT SUM(( 
                  SELECT `ItemAmount`*`PriceModifier`*(
                                         SELECT `SellingPrice` 
                                         FROM `Item` 
                                         WHERE `ID`=`BundleItem`.`ItemID`
                                         ) 
                   FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
                        ))
      ) AS `SellingPrice`,
      (
        SELECT SUM((
                   SELECT `ItemAmount`*(
                                        SELECT `Cost` 
                                        FROM `Item` 
                                        WHERE `ID`=`BundleItem`.`ItemID`
                                       )
                    FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
                  ))
      ) AS `Cost`, 
      1 AS `Bundle`
FROM `Bundle` 
WHERE `ID` IN (
               SELECT `BundleID` 
               FROM `BundleCategory` 
               WHERE `CategoryID`=8
              )

Возвращает

(1242): Subquery returns more than 1 row. 

Это происходит, даже когда я пытаюсь SELECT SUM((SELECT ID FROM Item)). Weird. Я прокомментировал другие решения о том, насколько хорошо они работают. Я ценю всех вас, ребята, принимающих участие в этом. <3 </p>

Ответы [ 4 ]

2 голосов
/ 19 апреля 2019

Похоже, у вас было несколько синтаксических проблем.Ваш код работал с несколькими изменениями.См. Комментарии в запросе для получения подробной информации.

http://sqlfiddle.com/#!9/ee0725/16

SELECT `ID`, `Name`, `Description`, `PictureID`, 
                  (SELECT SUM(`ItemAmount`*`PriceModifier`*( -- changed order of SELECT and SUM; removed extra SELECT; fixed Parens
                                         SELECT `SellingPrice` 
                                         FROM `Item` 
                                         WHERE `ID`=`BundleItem`.`ItemID`
                                         ))
                   FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`)
       AS `SellingPrice`,
                   (SELECT SUM(`ItemAmount`*( -- changed order of SELECT and SUM; removed extra SELECT; fixed Parens
                                        SELECT `Cost` 
                                        FROM `Item` 
                                        WHERE `ID`=`BundleItem`.`ItemID`
                                       ))
                    FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`)
       AS `Cost`, 
      1 AS `Bundle`
FROM `Bundle` 
WHERE `ID` IN (
               SELECT `BundleID` 
               FROM `BundleCategory` 
               WHERE `CategoryID`=8
              );
1 голос
/ 19 апреля 2019

Синтаксическая ошибка в том, что ваш подзапрос не заключен в ().Примеры ниже.

Это не удастся:

SELECT SUM(SELECT 1);

Это будет работать:

SELECT SUM((SELECT 1));
1 голос
/ 19 апреля 2019

Предположение № 1: У всех предметов должно быть достаточно запаса в городе, чтобы связка была доступна в этом городе.(См. Комментарии к запросу, чтобы узнать, как удалить это бизнес-правило.)

В примерах данных нет пакетов, которые полностью есть в наличии в каких-либо городах - чтобы исправить это, я изменил Quanity для ItemID = 4 в CityID= 1 от «1» до «5».Это создало желаемый результат.

Допущение # 2: Stock.Quantity = 0 разрешено.

Это решение создает результаты запроса, которые содержат все элементы и группы для каждого города и категории, в которой элемент илиПакет есть в наличии.Предложение where внизу фильтрует его по CityID = 1 и Category = 8 для исходного запроса.

Примечание. Вы можете вставить приведенное ниже решение и схему в www.sqlfiddle.com и посмотреть результаты.

ОБНОВЛЕНИЕ Исправлено объединение категорий Bundle.

Решение

select * from (
select 
    Stock.CityID,
    Item.CategoryID,
    Item.ID, 
    Item.Name, 
    Item.Description, 
    Item.SellingPrice, 
    Item.Cost,
    'false' as Bundle 
  from Item
  inner join Stock on Stock.ItemID = Item.ID
  where IFNULL(Stock.Quantity,0) > 0 -- remove this to show out of stock items
 union
  select 
    BundleSummary.CityID,
    BundleCategory.CategoryID,
    Bundle.ID, 
    Bundle.Name, 
    Bundle.Description, 
    BundleSummary.SellingPrice as SellingPrice,
    BundleSummary.Cost as Cost,
    'true' as Bundle 
  from Bundle 
    inner join (
      select
          BundleItem.BundleID, 
          City.CityID,
          MIN(IF(IFNULL(Stock.Quantity, 0) < BundleItem.ItemAmount, 0, 1)) as InStock,
          SUM(Item.SellingPrice * BundleItem.ItemAmount * BundleItem.PriceModifier) as SellingPrice,
          SUM(Item.Cost * BundleItem.ItemAmount) as Cost
        from BundleItem
          inner join Item on Item.ID = BundleItem.ItemID
          inner join (select distinct CityID from Stock where CityID IS NOT NULL) as City on 1=1
          left join Stock on Stock.ItemID = Item.ID and Stock.CityID = City.CityID
        group by BundleItem.BundleID, City.CityID
      ) as BundleSummary on BundleSummary.BundleID = Bundle.ID
    inner join BundleCategory on BundleCategory.BundleID = Bundle.ID
    where BundleSummary.InStock = 1 -- remove this to show out of stock bundles
) as qry1
where CityID=1 and CategoryID=8;

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

Схема

create table Item (
  ID int,
  Name varchar(255),
  Description varchar(255),
  PictureID int,
  SellingPrice DECIMAL(12,4),
  Cost DECIMAL(12,4),
  SupplierID int,
  CategoryID int
);
insert into Item values (1, 'Movie Ticket', '', NULL, 10, 2, NULL, 24);
insert into Item values (2, 'Box of Chocolates', '', NULL, 5, 1, NULL, 4);
insert into Item values (3, 'Teddy Bear', '', NULL, 15, 3, NULL, 2);
insert into Item values (4, 'Roses', '', NULL, 10, 4, NULL, 8);

create table Bundle (
  ID int,
  Name varchar(255),
  Description varchar(255),
  PictureID int
);
insert into Bundle values (1, 'Valentine Pack', 'Blah-blah tasty buy me', NULL);

create table Stock (
  ItemID int,
  CityID int,
  Quantity int,
  IsLimitless bit
);
insert into Stock values (1, 1, 25, false);
insert into Stock values (1, 2, 11, false);
insert into Stock values (2, 1, 84, false);
insert into Stock values (3, 1, 33, false);
insert into Stock values (4, 1, 5, true);
insert into Stock values (4, 3, 1, true);

create table BundleItem (
  BundleID int,
  ItemID int,
  ItemAmount int,
  PriceModifier DECIMAL(12,4)
);
insert into BundleItem values (1, 1, 2, 1.25);
insert into BundleItem values (1, 2, 1, 1);
insert into BundleItem values (1, 3, 1, 1);
insert into BundleItem values (1, 4, 5, 0.75);

create table BundleCategory (
  BundleID int,
  CategoryID int
);
insert into BundleCategory values (1, 4); -- Sweets
insert into BundleCategory values (1, 2); -- Toys
insert into BundleCategory values (1, 8); -- Flowers
1 голос
/ 19 апреля 2019

Примерно так должно работать

SELECT tb.`ID`, MAX(tb.`Name`), MAX(tb.`Description`), MAX(tb.`PictureID`), 
            SUM(`ItemAmount`*`PriceModifier`*`SellingPrice`) AS `SellingPrice`,
            SUM(`ItemAmount`*`Cost`) AS `Cost`, 
            1 AS `Bundle`
FROM `Bundle` tb 
JOIN `BundleItem` tbi on tb.ID=tbi.BundleID 
JOIN `Item` ti on tbi.ItemID=ti.ID
WHERE tb.`ID` IN (
               SELECT `BundleID` 
               FROM `BundleCategory` 
               WHERE `CategoryID`=?
              )
GROUP BY tb.ID
//No need to check bundles for stock due to business logic
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...