How to combine cell value to column name with CASE logic in SQL

北城以北 提交于 2019-12-25 04:24:10

问题


I have two VIEWS where data is represented as below:

VIEW 1

| username   |  function   |   level      | location       | 
|:-----------|------------:|:------------:| :-------------:|
| John       |   Operation |  Country     | United Kingdom | 
| John       |   Operation |  Area        | South West     |
| John       |   Operation |  Shop        | 0001           |

VIEW 2

| shop       |  region     |   country       |    area        | 
|:-----------|------------:|:---------------:| :-------------:|
| 1200       |   u1        |  United Kingdom |    West        | 
| 1201       |   u2        |  United Kingdom |    West        |
| 1000       |   f1        |  France         |  South West    | 
| 1100       |   i1        |  Italy          |  South West    |
| 1111       |   s1        |  Spain          |  South West    | 
| 1112       |   n2        |  Norway         |  South West    |
| 0001       |   o1        |  Japan          |  Asia          |

The relation between the two VIEWs are that each AREA has more than one Country, each Country has more than one REGION, each REGION has more than one shop.

Trying to: Generate a view where for each user from the top table data all rows will be generated from the bottom table depending on the LEVEL selection on the top table. So in this case the VIEW should show

Expected Result: So in this case the VIEW should show all the SHOPS, REGIONS, COUNTRIES under AREA South West, all the SHOPS and REGIONS under COUNTRY United Kingdom and the SHOP 0001.

| username   |  function   |   level         |    location    | 
|:-----------|------------:|:---------------:| :-------------:|
| John       |   Operation |    shop         |    0001        |
| John       |   Operation |    shop         |    1001        |
| John       |   Operation |    shop         |    ...         |
| John       |   Operation |    Country      |  United Kingdom|
| John       |   Operation |    Country      |    ...         |
| John       |   Operation |    Country      |    ...         |
| John       |   Operation |    Region       |    ...         |
| John       |   Operation |    Region       |    ...         |
| John       |   Operation |    Region       |    ...         |
| John       |   Operation |    Area         |    South West  | 
| John       |   Operation |    Area         |    ...         | 
| John       |   Operation |    Area         |    ...         | 

Not sure how this can be done with CASE statement. Any help would be appreciated.


回答1:


I think this will require a union of four separate queries:

  • The first query should select all shops equal to or under the shops/regions/countries/areas specified in the first table that join to the second table.
  • The second query should select all regions equal to or under the regions/countries/areas specified in the first table that join to the second table.
  • The third query should select all countries equal to or under the countries/areas specified in the first table that join to the second table.
  • The fourth query should select all areas specified in the first table that join to the second table.

There could be duplicates within each query, so we should use distinct within each query to eliminate them. There cannot be duplicates between the queries, so we can use union all rather than union.


create table userop (username varchar(32), [function] varchar(32), level varchar(32), location varchar(32) );
create table shopgeo (shop varchar(32), region varchar(32), country varchar(32), area varchar(32) );

insert into userop (username,[function],level,location) values
    ('John','Operation','Country','United Kingdom'),
    ('John','Operation','Area','South West'),
    ('John','Operation','Shop','0001')
;

insert into shopgeo (shop,region,country,area) values
    ('1200','u1','United Kingdom','West'),
    ('1201','u2','United Kingdom','West'),
    ('1000','f1','France','South West'),
    ('1100','i1','Italy','South West'),
    ('1111','s1','Spain','South West'),
    ('1112','n2','Norway','South West'),
    ('0001','o1','Japan','Asia')
;

-- show base tables
select * from userop;
select * from shopgeo;

-- solution
select * from (
    select distinct o.username, o.[function], 'shop' level, g.shop location from userop o inner join shopgeo g on o.location=case when o.level='Area' then g.area when o.level='Country' then g.country when o.level='Region' then g.region when o.level='Shop' then g.shop end
    union all select distinct o.username, o.[function], 'region' level, g.region from userop o inner join shopgeo g on o.location=case when o.level='Area' then g.area when o.level='Country' then g.country when o.level='Region' then g.region end
    union all select distinct o.username, o.[function], 'country' level, g.country from userop o inner join shopgeo g on o.location=case when o.level='Area' then g.area when o.level='Country' then g.country end
    union all select distinct o.username, o.[function], 'area' level, g.area from userop o inner join shopgeo g on o.location=case when o.level='Area' then g.area end
) t1 order by username, case when level='shop' then 1 when level='country' then 2 when level='region' then 3 when level='area' then 4 end, location;




回答2:


I did it slightly differently

DECLARE @user varchar(50) = 'John'

Declare @view1 table (
username varchar(50),
ufunction varchar(50),
ulevel varchar(50),
location varchar(50))

INSERT INTO @view1 VALUES ('John', 'Operation', 'Country', 'United Kingdom')
INSERT INTO @view1 VALUES ('John', 'Operation', 'Area', 'South West')
INSERT INTO @view1 VALUES ('John', 'Operation', 'Shop', '0001')

Declare @view2 table (
shop varchar(50),
region char(2),
country varchar(50),
area varchar(50))

INSERT INTO @view2 VALUES ('1200', 'u1', 'United Kingdom', 'West')
INSERT INTO @view2 VALUES ('1201', 'u2', 'United Kingdom', 'West')
INSERT INTO @view2 VALUES ('1000', 'f1', 'France', 'South West')
INSERT INTO @view2 VALUES ('1100', 'i1', 'Italy', 'South West')
INSERT INTO @view2 VALUES ('1111', 's1', 'Spain', 'South West')
INSERT INTO @view2 VALUES ('1112', 'n2', 'Norway', 'South West')
INSERT INTO @view2 VALUES ('0001', 'o1', 'Japan', 'Asia')

SELECT username, ufunction, v1.ulevel, location AS Shop, v2.region, v2.country, v2.area from @view1 v1 
INNER JOIN @view2 v2 ON v1.location = v2.shop
WHERE v1.ulevel = 'Shop' AND username = @user
UNION
SELECT v1.username, v1.ufunction, v1.ulevel, v2.shop, v2.region, v2.country, v2.area from @view1 v1
INNER JOIN @view2 v2 ON v1.location = v2.area
WHERE v1.ulevel = 'Area' AND username = @user
UNION
SELECT v1.username, v1.ufunction, v1.ulevel, v2.shop, v2.region, v2.country, v2.area from @view1 v1
INNER JOIN @view2 v2 ON v1.location = v2.country
WHERE v1.ulevel = 'Country' AND username = @user

RESULT

username    ufunction   ulevel  Shop    region  country         area
John        Operation   Area    1000    f1      France          South West
John        Operation   Area    1100    i1      Italy           South West
John        Operation   Area    1111    s1      Spain           South West
John        Operation   Area    1112    n2      Norway          South West
John        Operation   Country 1200    u1      United Kingdom  West
John        Operation   Country 1201    u2      United Kingdom  West
John        Operation   Shop    0001    o1      Japan           Asia

The idea being that you list all the shops just once, but that within each record you can read off what right gives the user access to that shop, be it "Shop", "Area" or "Country"



来源:https://stackoverflow.com/questions/39017835/how-to-combine-cell-value-to-column-name-with-case-logic-in-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!