tsql - Getting those records that have a match of all records in another table -
within realm of problem have 3 entities:
userpositionlicense
then have 2 relational (many-to-many) tables:
positionlicense- 1 connectspositionlicenseie. licenses required particular positionuserlicense- 1 connectsuserlicenseie. licenses particular user has. additional complexity: user licenses have validity date range (validfrom,validto)
the problem
these input variables:
userididentifiers particularuserrangefromdefines lower date range limitrangetodefines upper date range limit
what need get? particular user (and date range) need list of positions particular user can work at. problem user must have @ least licenses required every matching position.
i'm having huge problems writing sql query list.
if @ possible using single sql query (can have additional ctes of course). if can convince me doing in several queries more efficient i'm willing listen in.
some workable data
copy , runs script. 3 users, 3 positions, 6 licenses. mark , john should have match not jane.
create table [user] ( userid int identity not null primary key, name nvarchar(100) not null ) go create table position ( positionid int identity not null primary key, name nvarchar(100) not null ) go create table license ( licenseid int identity not null primary key, name nvarchar(100) not null ) go create table userlicense ( userid int not null references [user](userid), licenseid int not null references license(licenseid), validfrom date not null, validto date not null, check (validfrom < validto), primary key (userid, licenseid) ) go create table positionlicense ( positionid int not null references position(positionid), licenseid int not null references license(licenseid), primary key (positionid, licenseid) ) go insert [user] (name) values ('mark mechanic'); insert [user] (name) values ('john pilot'); insert [user] (name) values ('jane has arts phd not medical.'); insert position (name) values ('mechanic'); insert position (name) values ('pilot'); insert position (name) values ('doctor'); insert license (name) values ('mecha'); insert license (name) values ('flying'); insert license (name) values ('medicine'); insert license (name) values ('phd'); insert license (name) values ('phycho'); insert license (name) values ('arts'); insert positionlicense (positionid, licenseid) values (1, 1); insert positionlicense (positionid, licenseid) values (2, 2); insert positionlicense (positionid, licenseid) values (2, 5); insert positionlicense (positionid, licenseid) values (3, 3); insert positionlicense (positionid, licenseid) values (3, 4); insert userlicense (userid, licenseid, validfrom, validto) values (1, 1, '20110101', '20120101'); insert userlicense (userid, licenseid, validfrom, validto) values (2, 2, '20110101', '20120101'); insert userlicense (userid, licenseid, validfrom, validto) values (2, 5, '20110101', '20120101'); insert userlicense (userid, licenseid, validfrom, validto) values (3, 4, '20110101', '20120101'); insert userlicense (userid, licenseid, validfrom, validto) values (3, 6, '20110101', '20120101'); resulting solution
i've setup resulting solution based on accepted answer provides simplified solution problem. if you'd play query hit edit/clone (whether you're logged in or not). can changed:
- three variables:
- two variable set date range (
@from,@to) - user id (
@user)
- two variable set date range (
- you can toggle commented code in first cte switch code between overlapping user licenses or partially overlapping ones.
this makes number of assumptions (ignores presence of time in datetime columns, assumes obvious primary keys) , skips joins pull in user name, position details, , like. (and implied user had hold licenses full period specified, right?)
select pl.positionid positionlicense pl left outer join (-- licenses user has entirety (sp?) of specified date range select licenseid userlicense userid = @userid , @rangefrom <= validfrom , @rangeto >= validto) li on li.licenseid = pl.licenseid group pl.positionid -- licenses required position held user having count(pl.licenseid) = count(li.licenseid) no data can't debug or test it, or close should trick.
Comments
Post a Comment