问题
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