Domanda

I am trying to write a query to determine how much of my inventory is committed at a given time, i.e. current, next month, etc.

A simplified example:

I have an inventory table of items. I have an offer table that specifies the customer, when the offer starts, and when the offer expires. I have a third table that associates the two.

create table inventory
(id int not null auto_increment , name varchar(32) not null, primary key(id));

create table offer
(id int not null auto_increment , customer_name varchar(32) not null, starts_at datetime not null,  expires_at datetime, primary key (id));

create table items
(id int not null auto_increment, inventory_id int not null, offer_id int not null, primary key (id),
  CONSTRAINT fk_item__offer FOREIGN KEY (offer_id)  REFERENCES offer(id),
  CONSTRAINT fk_item__inventory FOREIGN KEY (inventory_id)  REFERENCES inventory(id));

create some inventory

insert into inventory(name)
    values ('item 1'), ('item 2'),('item 3');

create two offers for this month

insert into offer(customer_name, starts_at)
    values ('customer 1', DATE_FORMAT(NOW(), '%Y-%m-01')), ('customer 2', DATE_FORMAT(NOW(), '%Y-%m-01'));

and one for next month

insert into offer(customer_name, starts_at)
    values ('customer 3', DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01'));

Now add some items to each offer

insert into items(inventory_id, offer_id)
    values (1,1), (2,1), (2,2), (3,3);

What I want is a query that will show me all the inventory and the count of the committed inventory for this month. Inventory would be considered committed if the starts_at is less than or equal to now, and the offer has not expired (expires_at is null or expires_at is in the future)

The results I would expect would look like this:

+----+--------+---------------------+
| id | name   | committed_inventory |
+----+--------+---------------------+
|  1 | item 1 |                   1 |
|  2 | item 2 |                   2 |
|  3 | item 3 |                   0 |
+----+--------+---------------------+
3 rows in set (0.00 sec)

The query that I felt should work is:

SELECT inventory.id
     , inventory.name
     , count(items.id) as committed_inventory
  FROM inventory
  LEFT JOIN items
    ON items.inventory_id = inventory.id
  LEFT JOIN offer
    ON offer.id = items.offer_id
 WHERE (offer.starts_at IS NULL OR offer.starts_at <= NOW())
   AND (offer.expires_at IS NULL OR offer.expires_at > NOW())
 GROUP BY inventory.id, inventory.name;

However, the results from this query does not include the third item. What I get is this:

+----+--------+---------------------+
| id | name   | committed_inventory |
+----+--------+---------------------+
|  1 | item 1 |                   1 |
|  2 | item 2 |                   2 |
+----+--------+---------------------+
2 rows in set (0.00 sec)

I cannot figure out how to get the third inventory item to show. Since inventory is the driving table in the outer joins, I thought that it should always show.

È stato utile?

Soluzione

The problem is the where clause. Try this:

SELECT inventory.id
     , inventory.name
     , count(offers.id) as committed_inventory
  FROM inventory
  LEFT JOIN items
    ON items.inventory_id = inventory.id
  LEFT JOIN offer
    ON offer.id = items.offer_id and
       (offer.starts_at <= NOW() or
        offer.expires_at > NOW()
      )
 GROUP BY inventory.id, inventory.name;

The problem is that you get a matching offer, but it isn't currently valid. So, the where clause fails because the offer dates are not NULL (there is a match) and the date comparison fails because the offer is not current ly.

Altri suggerimenti

For item 3 the starts_at from offer table is set to March, 01 2014 which is greater than NOW so (offer.starts_at IS NULL OR offer.starts_at <= NOW()) condition will skip the item 3 record

See fiddle demo

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top