Как объединить 3 таблицы без потери строк? - PullRequest
0 голосов
/ 05 мая 2018

Я пытаюсь написать запрос, который объединяет три таблицы, группы по столбцу id и находит максимальное значение столбца. Однако, если для данной строки нет значений, вся строка таблицы удаляется из набора результатов.

У меня есть аукционный сайт, с разными предметами. Я показываю price как max(bid) рядом с элементом на странице, который называется активными ставками. Моя проблема в том, что если у предмета нет ставок, он не появляется на странице, пока не получит свою первую ставку.

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

Можно ли отобразить max(bid) как пустое, но все же заставить элемент появляться? Короче говоря, я спрашиваю, как я могу отобразить строку таблицы, даже если в один из столбцов не вставлено значение (в столбце есть null принято, но по-прежнему нет результата).

Вот мой запрос:

SELECT COALESCE(max(bid.amount) , 0) AS amount, item.img, item.expirydate, item.iditem, item.description, item.min_price, seller.name  
FROM item,seller,bid 
WHERE seller.idseller=item.idseller 
AND idcategory=1
  and
bid.iditem=item.iditem
AND item.expirydate> curdate()
group by iditem;" 
    ;

PHP:

<?php $datasett = $tilkobling->query($sql);
<?php  while ($rad=mysqli_fetch_array($datasett)) { ?>
    <tr>
        <div class="artikkelbilde" id="tabell">
            <td>
                <img class="artikkelbilde" src="../images/<?php echo $rad ["img"];?>">
            </td>
            </td>
        </div>
        <td>
            <?php echo $rad["iditem"]; ?>
        </td>
        <td>
            <?php echo $rad["description"]; ?>
        </td>
        <td>
            <?php echo $rad["min_price"]; ?>
        </td>
        <td>
            <?= $rad["name"]; ?>
        </td>
        <td>
            <?php echo $rad["expirydate"]; ?>
        </td>
        <td>
            <?php echo $rad["amount"]; ?>
        </td>
        <td>
            <a href="Gibud.php"> Gi bud </a>
        </td>
<?php } ?>`

Вот SQL для трех соответствующих таблиц, с абсолютным минимальным количеством информации, но принцип должен быть таким же. Я просто пытаюсь получить sql для получения предметов, когда у предмета нет ставок:

CREATE TABLE `bid` (
   `idbid` INT NOT NULL AUTO_INCREMENT,
   `amount` INT NOT NULL,
   `idbuyer` INT NULL,
   `iditem` INT NULL,
   PRIMARY KEY (`idbid`)
);

CREATE TABLE `item` (
   `iditem` INT NOT NULL AUTO_INCREMENT,
   `min_price` INT NULL,
   `description` VARCHAR(45) NULL,
   `idseller` INT NULL,
   `idcategory` INT NULL,
   PRIMARY KEY (`iditem`)
);

CREATE TABLE `seller` (
    `idseller` INT NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(45) NULL,
    PRIMARY KEY (`idseller`)
);

ALTER TABLE `bid` 
    ADD INDEX `FK_item_idx` (`iditem` ASC);
ALTER TABLE `bid` 
    ADD CONSTRAINT `FK_item`
    FOREIGN KEY (`iditem`)
    REFERENCES `item` (`iditem`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION;

ALTER TABLE `item` 
    ADD INDEX `FK_seller_idx` (`idseller` ASC);
ALTER TABLE `item` 
    ADD CONSTRAINT `FK_seller`
    FOREIGN KEY (`idseller`)
    REFERENCES `seller` (`idseller`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION;

INSERT INTO `item` (`min_price`, `description`) VALUES ('200', 'coffeetable');
INSERT INTO `item` (`min_price`, `description`) VALUES ('400', 'lamp');
INSERT INTO `item` (`min_price`, `description`) VALUES ('600', 'painting');

INSERT INTO `bid` (`amount`, `iditem`) VALUES ('800', '1');
INSERT INTO `bid` (`amount`,`iditem`) VALUES ('1000','2');

INSERT INTO `seller` (`name`) VALUES ('Bob');
INSERT INTO `seller` (`name`) VALUES ('Rob');
INSERT INTO `seller` (`name`) VALUES ('Tob');

UPDATE `item` SET `idseller`='1' WHERE `iditem`='1';
UPDATE `item` SET `idseller`='1' WHERE `iditem`='2';
UPDATE `item` SET `idseller`='2' WHERE `iditem`='3';

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Вам необходимо написать правильные JOINS в вашем запросе, а не полагаться на оператор FROM [table1, table2], поскольку он использует только обычный JOIN.

Возможно, вы захотите что-то вроде этого:

SELECT 
   COALESCE(max(bid.amount) , 0) AS amount, 
   item.img, 
   item.expirydate, 
   item.iditem, 
   item.description, 
   item.min_price, 
   seller.name  
FROM item 
LEFT JOIN seller on seller.idseller = item.idseller
INNER JOIN bid on bid.iditem = item.iditem

WHERE 
   item.expirydate > curdate()
   # add your idcategory here, prefixed with the tablename

GROUP BY item.iditem;

PS: я не добавил ваш idcategory=1, потому что я не уверен, в какой таблице это происходит.

INNER JOIN попытается присоединиться к записи, если эта запись не найдена, он добавит null значений для каждого поля INNER JOINED, которое вы хотите выбрать, COALESCE выберет либо первый аргумент, либо второй, если первый null.

0 голосов
/ 06 мая 2018

На основании опубликованных образцов данных для трех таблиц вы можете использовать пару LEFT JOIN s, чтобы обеспечить сохранение всех значений iditem. Следовательно, когда объединенные таблицы не синхронизируются с таблицами слева от них, вы увидите некоторые значения NULL.

SELECT `item`.`iditem`, 
       COALESCE(MAX(`bid`.`amount`), 0) AS `amount`,
       `item`.`description`,
       `item`.`min_price`,
       `seller`.`name`  
FROM `item`
LEFT JOIN `seller` ON `seller`.`idseller` = `item`.`idseller`
LEFT JOIN `bid` ON `bid`.`iditem` = `item`.`iditem`
WHERE `item`.`idcategory` IS NULL  /* because you didn't give this bit of data, nor the expiry */
GROUP BY `item`.`iditem`;

Вот моя демоверсия sqlfiddle , чтобы доказать успешность запроса на ваших образцах данных.

При выполнении СОЕДИНЕНИЙ вы должны включать в себя предложение ON, которое определяет, какие столбцы действуют как клей.

Предложение WHERE теперь в вашем распоряжении для настройки в соответствии с требованиями вашего проекта. Не забудьте уточнить, из какой таблицы поступают определенные столбцы, чтобы избежать ошибок из-за неоднозначности.

Имена таблиц и столбцов с обратной косой чертой могут быть излишними (а некоторым разработчикам не нравится раздувание), но я считаю, что это разумно, если исключить возможность случайного использования зарезервированного слова mysql.

0 голосов
/ 05 мая 2018

Вы когда-нибудь использовали COALESCE в MySQL ??

Я думаю, у вас должно быть что-то подобное в вашем запросе

SELECT COALESCE(max(bid) , 0) AS max_bid FROM tables1

COALESCE возвращает первое ненулевое выражение в списке

...