I have 2 tables like that:
PermissionsTbl
__________________
PermissionID int NotNull
PermissionDescription nvarchar(100) NotNull
PermissionID PermissionDescription
1 Human Resources
2 Employees Data
3 Departements
ActivePermissionsTbl
________________________
ActivePermID bigint NotNull
PermissionID int NotNull
UserID int NotNull
PageActive bit NotNull
ActivePermID PermissionID UserID PageActive
1 1 1 True
2 2 1 True
3 3 2 True
what I want is show data like that:
PermissionID PermissionDescription PageActive UserID
1 Human Resources True 1
2 Employees Data True 1
3 Departements 1
1 Human Resources 2
2 Employees Data 2
3 Departements True 2
I try several methods of Join , but I failed< any suggestion please.
Thanks.
I'm sure someone can find a more elegant/efficient solution, but this appears to give you what you need:
SELECT
a.PermissionID ,
A.PermissionDescription ,
ISNULL(ap.PageActive , 0) 'PageActive' ,
a.UserID
FROM
(
SELECT DISTINCT
*
FROM permissionstbl p
CROSS JOIN
(
SELECT
userid
FROM activepermissionstbl
)
a
)
a
LEFT JOIN activepermissionstbl ap ON ap.userid = a.userid AND ap.permissionid = a.permissionid
ORDER BY a.userid
So the inner query gets the Cartesian product of the two tables and then distincts them. Then for each one of those results it gets the appropriate permission in the active permissions table.
Using a left join for this so that any null results means they don't currently have an activepermission and thus the pageactive value is false.
View Demo Here
Related
I have a question about the Any-Operator.
On Technet it says
For example, the following query finds customers located in a territory not covered by any sales persons.
Use AdventureWorks2008R2;
GO
SELECT
CustomerID
FROM
Sales.Customer
WHERE
TerritoryID <> ANY
(
SELECT
TerritoryID
FROM
Sales.SalesPerson
);
Further
The results include all customers, except those whose sales territories are NULL, because every territory that is assigned to a customer is covered by a sales person. The inner query finds all the sales territories covered by sales persons, and then, for each territory, the outer query finds the customers who are not in one.
But that query returns all customers.
I updated a customers TerritoryID to a value that no sales.person has, but still that query returns all customers, instead of that one I expected ..
Am I missing something ?
Might it be that that article on technet is simply wrong ?
https://technet.microsoft.com/de-de/library/ms187074(v=sql.105).aspx (german)
There is one customer with TerritoryID = 13
Inner query result (SELECT TerritoryID FROM Sales.SalesPerson) :
4
2
4
3
6
5
1
4
6
1
1
6
9
1
8
10
7
And in table Sales.Customer is a row with CustomerID = 13, which is the one not covered by a sales-person..
create table #t1
(
id int
)
insert into #t1
values(1),(2),(3)
As you can see,T1 has three values
now lets see,how Any Works
When 'is Equal to ' is used with any ,it works like IN
select * from #t1 where id=
any(select 0)--no result
when Any is used with > or <> ,Any means get me all the values which are greater than minimum value
select * from #t1 where id<>
any(select 1)--2,3
select * from #t1 where id<>
any(select 0)--1,2,3
If your subquery returns one value,the outer query will try to get values which are greater than inner query
<> ANY means any Sales.Customer with a TerritoryID that is Greater Than or Less Than any of the TerritoryID's in the Sales.SalesPerson
so TerritoryID = 13 is greater than all or your examples (4 2 4 3 6 5 1 4 6 1 1 6 9 1 8 10 7), so it's included.
<> ALL is the equivalent of NOT IN so that is what you're confusing <> ANY with
Look at <> ANY as, if there are any records in the set that are not equal to the quailifier, then include it.
The following query has the same result:
SELECT CustomerID FROM Sales.Customer
WHERE TerritoryID NOT IN (SELECT TerritoryID FROM Sales.SalesPerson)
This is my first post - so I apologise if it's in the wrong seciton!
I'm joining two tables with a one-to-many relationship using their respective ID numbers: but I only want to return the most recent record for the joined table and I'm not entirely sure where to even start!
My original code for returning everything is shown below:
SELECT table_DATES.[date-ID], *
FROM table_CORE LEFT JOIN table_DATES ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
ORDER BY [table_CORE].[core-ID], [table_DATES].[iteration];
This returns a group of records: showing every matching ID between table_CORE and table_DATES:
table_CORE date-ID iteration
1 1 1
1 1 2
1 1 3
2 2 1
2 2 2
3 3 1
4 4 1
But I need to return only the date with the maximum value in the "iteration" field as shown below
table_CORE date-ID iteration Additional data
1 1 3 MoreInfo
2 2 2 MoreInfo
3 3 1 MoreInfo
4 4 1 MoreInfo
I really don't even know where to start - obviously it's going to be a JOIN query of some sort - but I'm not sure how to get the subquery to return only the highest iteration for each item in table 2's ID field?
Hope that makes sense - I'll reword if it comes to it!
--edit--
I'm wondering how to integrate that when I'm needing all the fields from table 1 (table_CORE in this case) and all the fields from table2 (table_DATES) joined as well?
Both tables have additional fields that will need to be merged.
I'm pretty sure I can just add the fields into the "SELECT" and "GROUP BY" clauses, but there are around 40 fields altogether (and typing all of them will be tedious!)
Try using the MAX aggregate function like this with a GROUP BY clause.
SELECT
[ID1],
[ID2],
MAX([iteration])
FROM
table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE
table_CORE.[core-ID] Like '*' --LIKE '%something%' ??
GROUP BY
[ID1],
[ID2]
Your example field names don't match your sample query so I'm guessing a little bit.
Just to make sure that I have everything you’re asking for right, I am going to restate some of your question and then answer it.
Your source tables look like this:
table_core:
table_dates:
And your outputs are like this:
Current:
Desired:
In order to make that happen all you need to do is use a subquery (or a CTE) as a “cross-reference” table. (I used temp tables to recreate your data example and _ in place of the - in your column names).
--Loading the example data
create table #table_core
(
core_id int not null
)
create table #table_dates
(
date_id int not null
, iteration int not null
, additional_data varchar(25) null
)
insert into #table_core values (1), (2), (3), (4)
insert into #table_dates values (1,1, 'More Info 1'),(1,2, 'More Info 2'),(1,3, 'More Info 3'),(2,1, 'More Info 4'),(2,2, 'More Info 5'),(3,1, 'More Info 6'),(4,1, 'More Info 7')
--select query needed for desired output (using a CTE)
; with iter_max as
(
select td.date_id
, max(td.iteration) as iteration_max
from #table_dates as td
group by td.date_id
)
select tc.*
, td.*
from #table_core as tc
left join iter_max as im on tc.core_id = im.date_id
inner join #table_dates as td on im.date_id = td.date_id
and im.iteration_max = td.iteration
select *
from
(
SELECT table_DATES.[date-ID], *
, row_number() over (partition by table_CORE date-ID order by iteration desc) as rn
FROM table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
) tt
where tt.rn = 1
ORDER BY [core-ID]
I have three tables :
1) UserTable
UserId UserName
1 Mike
2 John
3 Jennifer
2) FormName
fID fName
1 edit
2 cafe
3 backoffice
3)User to form
fId UserId Allowed(bit)
1 1 0
2 1 1
3 1 1
2 2 1
3 2 0
The first table is the user table with user informations.
The second table is the form table where it stores form names of application
The third table is user level table where it says which user is allowed to open which form .
I want to create sql query where I can see all information in a single table like :
UserId USerName Edit Cafe BackOffice
1 mike 0 1 1
2 john 1 1 0
I think it is possbile with SQL Fiddle and Pivot but I am having hard time to figure the right code out .
You can use the PIVOT function, but you have to cast the allowed column to something other than a bit datatype. For example, the below casts it to an int:
select userid, username,
coalesce(Edit, 0) Edit,
coalesce(Cafe, 0) Cafe,
coalesce(BackOffice, 0) BackOffice
from
(
select u.userid,
u.username,
f.fname,
cast(allowed as int) allowed
from usertable u
inner join user_form uf
on u.userid = uf.userid
inner join formname f
on uf.fid = f.fid
) d
pivot
(
max(allowed)
for fname in (Edit, Cafe, BackOffice)
) piv;
See SQL Fiddle with Demo
I'm trying to write a ranked match/searching system for a client that will look at the materials requested (MaterialRequest table) and find the providers (where userprofile.usertype_id = 1) who can provide the material(s) and rank the results that can provide the most, or all of the, materials. Here's the database schema i have:
Userprofile Table
userprofile_id int identity
userprofile_dt datetime
first_nm varchar(50)
last_nm varchar(50)
usertype_id int (provider = 1, requestor = 2)
Request Table
request_id int identity
request_dt datetime
title varchar(50)
description varchar(100)
userprofile_id int (where usertype = 2)
MaterialRequest Table
material_req_id int identity
request_id int
material_id int
MaterialProvider Table
material_pro_id int identity
userprofile_id int (where usertype = 1)
material_id int
Material Table
material_id int identity
material_desc varchar(50)
So, for example, if I have this request:
request_id = 1
request_dt = 3/28/2011
title = 'test request'
desc = null
userprofile_id = 100 (where usertype_id = 2)
and these materials were requested
material_req_id request_id material_id
1 1 10 (steel)
2 1 11 (copper)
3 1 12 (titanium)
4 1 13 (nickel)
and the MaterialProvider was populated like
material_pro_id userprofile_id material_id
1 2 10 (steel)
2 2 11 (copper)
3 2 13 (nickel)
4 3 11 (copper)
5 3 13 (nickel)
6 3 12 (titanium)
I would expect my output to look like
userprofile_id steel copper nickel titanium pct_match
2 Y Y Y N 75
3 N Y Y Y 75
where the column names are derived from the materials in the request. Then be able to find the providers that can provide more than a given percentage of the materials requested.
I had started with a temporary table and a cursor to
add the columns to the temporary table
then iterate through the 3000+ providers and add those providers that can provide the specified materials.
Is there a better way to do this? The process takes way too long and would like to get better/best practices on how to write something like this.
;WITH NormalOutput AS (
/* normal output: one material per row */
SELECT
p.userprofile_id,
m.material_desc,
value = CASE WHEN mp.material_pro_id IS NULL THEN 'N' ELSE 'Y' END
FROM Request r
INNER JOIN MaterialRequest mr ON r.request_id = mr.request_id
INNER JOIN Material m ON mr.material_id = m.material_id
CROSS JOIN (SELECT DISTINCT userprofile_id FROM MaterialProvider) p
LEFT JOIN MaterialProvider mp
ON p.userprofile_id = mp.userprofile_id AND mr.material_id = mp.material_id
WHERE r.request_id = 1
)
SELECT p.*, t.pct_match
FROM (
/* pivoting the normal output */
SELECT userprofile_id, steel, copper, titanium, nickel
FROM NormalOutput n
PIVOT (MAX(value) FOR material_desc IN (steel, copper, titanium, nickel)) p
) p
INNER JOIN (
/* aggregating the normal output (calculating percents) */
SELECT
userprofile_id,
pct_match = COUNT(CASE value WHEN 'Y' THEN value END) * 100 / COUNT(*)
FROM NormalOutput
GROUP BY userprofile_id
) t
/* joining the two modified outputs */
ON t.userprofile_id = p.userprofile_id
Do the pivot on the materials name last, after you've identified a set of target providers. Do all the math first, then the pretty formatting.
Does anyone know how can I add an integer from another table to the current selected table in SQL Server?
For example:
I have 2 tables with the following information in each table
tableA:
id username point status country
1 alvin 1 1 U.S.A
2 alvin 1 1 U.S.A
3 amy 1 0 Australia
tableB:
id username point
1 amy 1
2 alvin 1
3 ken 1
How can I sum up the total points in tableA with also add in the sum points from tableB?
I tried the following code, but seem is not working and error display:
SELECT username, (COUNT(distinct a.point) + (SELECT SUM(a.point)
FROM tableB b WHERE b.username = a.username) AS 'Points', status, country
FROM tableA
GROUP BY aco.username
And the output I expected will be:
username Points status country
alvin 3 1 U.S.A
amy 2 0 Australia
WITH Results(username,point)
AS
(
SELECT username, point FROM TableA
UNION ALL
SELECT username, point FROM TableB
)
SELECT username, sum(point) AS Points FROM Results GROUP BY username
GO
EDIT
The question has changed, so now the solution should look like this
WITH Results(username,point,status, country)
AS
(
SELECT username, point, status, country FROM TableA
UNION ALL
SELECT username, point, null, null FROM TableB
)
SELECT username, sum(point) AS Points, max(status), max(country) FROM Results GROUP BY username
GO
What is WITH ?
What is UNION ?
You don't mention why Ken doesn't appear in the output table, I assume that TableA is the 'master' list. If so I would do the following INNER JOIN which is the most simple solution.
SELECT a.username AS Username, SUM(ISNULL(a.point,0)+ISNULL(b.point,0)) as Points,
MAX(a.Status) as Status, MAX(a.Country) as Country
FROM TableA a
INNER JOIN TableB b
ON a.username=b.username
GROUP BY a.username