推断而不是where子句

时间:2014-10-31 15:20:57

标签: sql where-clause

我正在尝试简化where子句,因此我不必列出表格中的每一列。

一个例子是这样的:

选择仅包含Gin,Rum,Vodka的Drink_Names。

SELECT Drink_Name
FROM Answer
WHERE Gin IS NOT NULL 
AND Rum IS NOT NULL 
AND Vodka IS NOT NULL 
AND Lager IS NULL 
AND Cider IS NULL
AND Tequila IS NULL
AND Whiskey IS NULL
AND Baileys IS NULL
AND Cola IS NULL

平台设计:

Drink_Name      Baileys Cider   Cola    Gin    Lager    Rum   Tequila Vodka Whiskey
Mary Hinge      NULL    NULL    NULL    NULL    NULL       1    NULL    NULL       1
Ringsting       NULL       1       1    NULL    NULL    NULL       1    NULL       1
Stonehenge      NULL       1    NULL       1       1       1    NULL       1    NULL
Typhoon Lagoon  NULL    NULL    NULL       1    NULL       1    NULL       1    NULL
Wet and Wild       1    NULL       1    NULL    NULL    NULL       1       1    NULL

推荐设计

饮料表:

    Drink_NameID
    Drink_Name

成分表:

    Drink_NameID
    Ingredient_Name

饮料表数据:

    Mary Hinge
    Ringsting
    Stonehenge
    Typhoon Lagoon
    Wet and Wild

成分表数据:

    Baileys
    Cider
    Cola
    Gin
    Lager
    Rum
    Tequila
    Vodka
    Whiskey

1 个答案:

答案 0 :(得分:0)

(这不是一个答案,但对评论来说太大了)

您要求简化您的where子句,以便选择仅包含Gin,Rum,Vodka的Drink_Names

在您当前的版本中,您的查询将如下所示:

SELECT Drink_Name 
FROM Answer 
WHERE Gin IS NOT NULL  AND Rum IS NOT NULL AND Vodka IS NOT NULL;

你被告知要让你的结构变得更好。好的,你的结构看起来像这样(我省略了外键,ids等):

create view good_structure as 
select drink_name, drink_type, amount from answer 
unpivot exclude nulls(
  amount for drink_type in (baileys as 'baileys', cider as 'cider', cola as 'cola', gin as 'gin', lager as 'lager', 
                            rum as 'rum', tequila as 'tequila', vodka as 'vodka', whiskey as 'whiskey')
);

通过这种良好的结构,我们可以简化您的查询:

SELECT distinct Drink_Name 
FROM good_structure g
WHERE exists (select 1 from good_structure g2 where g2.drink_name = g.drink_name and g2.drink_type = 'Gin' and g2.amount > 0)
  AND exists (select 1 from good_structure g2 where g2.drink_name = g.drink_name and g2.drink_type = 'Rum' and g2.amount > 0)
  AND exists (select 1 from good_structure g2 where g2.drink_name = g.drink_name and g2.drink_type = 'Vodka' and g2.amount > 0);

更简单:)

因此,如果您的目的是简化查询,那么当前的简单就足够了。如果你想要一个好的设计而不是我想它是另一个问题......

这是一些重构脚本,可以帮助您理解:

-- remove all
drop table drink_recipes;
drop table ingredients;
drop table drinks;

drop sequence drinks_seq;
drop sequence ingredients_seq;
drop sequence drink_recipes_seq;

-- create tables
create table DRINKS (drink_id number(10) primary key, drink_name varchar2(255));
create table INGREDIENTS (ingredient_id number(10) primary key, ingredient_name varchar2(255));
create table DRINK_RECIPES (
  recipe_id number(10) primary key, 
  drink_id number(10) references DRINKS(drink_id), 
  ingredient_id number(10) references INGREDIENTS(ingredient_id), 
  amount number(5)
);
-- recipe_id may be redundant

-- create sequences (if needed)
create sequence drinks_seq;
create sequence ingredients_seq;
create sequence drink_recipes_seq;


-- fill the data
insert into drinks
select drinks_seq.nextval, drink_name from (select distinct drink_name from answer);

insert into INGREDIENTS
with unpivoted as (
  select drink_name, drink_type, amount from answer 
  unpivot exclude nulls(
    amount for drink_type in (baileys as 'baileys', cider as 'cider', cola as 'cola', gin as 'gin', lager as 'lager', 
                              rum as 'rum', tequila as 'tequila', vodka as 'vodka', whiskey as 'whiskey')
  )
)
select ingredients_seq.nextval, drink_type from (
select distinct drink_type from unpivoted);


insert into DRINK_RECIPES
with unpivoted as (
  select drink_name, drink_type, amount from answer 
  unpivot exclude nulls(
    amount for drink_type in (baileys as 'baileys', cider as 'cider', cola as 'cola', gin as 'gin', lager as 'lager', 
                              rum as 'rum', tequila as 'tequila', vodka as 'vodka', whiskey as 'whiskey')
  )
),
help as (
  select d.drink_id, i.ingredient_id, u.amount 
   from unpivoted u join drinks d on u.drink_name = d.drink_name
                    join ingredients i on u.drink_type = i.ingredient_name
)
select drink_recipes_seq.nextval, drink_id, ingredient_id, amount from help;