I have a Fact Table That has the list of all courses that every employee in the company has been passed.
FactPassedCourse: (CourseKey, EmployeeKey, DateKey)
DimEmployee: (EmployeeKey)
DimCourse: (CourseKey)
DimEmployee
Emp1 , Emp2
DimCourse
Course1, Course2, Course3, Course4, Course5
FactPassedCourse
-----------------------------------------
(Emp1, Course1, DateKey1)
(Emp1, Course2, DateKey2)
(Emp1, Course2, DateKey3)
(Emp1, Course3, DateKey3)
(Emp1, Course4, DateKey3)
(Emp2, Course4, DateKey1)
(Emp2, Course5, DateKey5)
DimEmployee & DimCourse Has Regular Relationship With FactPassedCourse in my Cube.
I want to get the count of Employees based on every courses but if an employee passed a special course(like Course2) more than once, the employee must be counted just one time I mean this result I want:
MDX result:
(Coursename: Course1 Employee_Count: 1)
(Coursename: Course2 Employee_Count: 1:because ONE employee passed this course two times)
(Coursename: Course3 Employee_Count: 1)
(Coursename: Course4 Employee_Count: 2: because two different employees passed this course)
(Coursename: Course5 Employee_Count: 1)
In order to get this result I wrote this mdx query and this return the correct result but the performance of this query is very slow.
With
Member [measures].[Employee_Count] as
Count(
Filter(
[DimEmployee].EmployeeKey].members-[DimEmployee].[EmployeeKey].[All]),
[measures].[FactPassedCourseCount]>0)
)
Set [Course_Set] as
Filter(
([DimCourse].[CourseKey].members–[DimCourse].CourseKey].[All]),
[measures].[FactPassedCourseCount] > 0
)
Select
[measures].[Employee_Count] on 0
, [Course_Set] on 1
From MyCube
This Query Result is:
(Coursename: Course1 Employee_Count: 1)
(Coursename: Course2 Employee_Count)
(Coursename: Course3 Employee_Count: 1)
(Coursename: Course4 Employee_Count)
(Coursename: Course5 Employee_Count: 1)
is there a better way to write this mdx query that have fast performance?
Is this quicker?
With
Member [measures].[Employee_Count] as
Count(
EXISTING
NONEMPTY(
[DimEmployee].[EmployeeKey].[EmployeeKey]
,[measures].[FactPassedCourseCount]
)
)
Select
[measures].[Employee_Count] on 0
, NONEMPTY(
[DimCourse].[CourseKey].[CourseKey]
,[measures].[FactPassedCourseCount]
) on 1
From [MyCube];
An alternative to the accepted answer -
with member [measures].[Employee_Count] AS
NonEmpty
(
[DimEmployee].EmployeeKey].[EmployeeKey].members,
([DimCourse].[CourseKey].Currentmember, [measures].[FactPassedCourseCount])
).Count
Select
[measures].[Employee_Count] on 0
, [Course_Set] on 1
From MyCube
Further, if you want to do filtering based on any value, there is a way to do that without using filter.
with
member measures.GrtThan5 as
IIF(
[Measures].[Claim As Of - Count] > 5,
1,
NULL
)
The definition would have to change to below -
member [measures].[Employee_Count] AS
NonEmpty
(
[DimEmployee].EmployeeKey].[EmployeeKey].members,
([DimCourse].[CourseKey].Currentmember, [measures].GrtThan5)
).Count
Related
I have two columns gender(values = 'Male' , 'Female') and grade(values = 'senior officer' , 'Junior Officer') and the table name is employee. I want to count all Males who are senior officers and all Males who are junior officers, vise versa for all females. Below is my code
''' SELECT staff_gender, staff_grade COUNT(*)
FROM permanent_staff
WHERE staff_gender='Female' AND staff_grade='senior officer' '''
Aggregate.
SELECT staff_gender, staff_grade
, COUNT(*) AS total
FROM permanent_staff
GROUP BY staff_gender, staff_grade
ORDER BY staff_gender, staff_grade
Imagine it like a student quiz.
10 Students get a C.
6 Students get a B.
1 Student gets an A.
Rather than showing that 1 student got an A, is there a way to show the name of the student that got that result?
This is part of the result set I get. The 2 letters represent the 2 first letters of a 6 letter string corresponding to a shelf and its warehouse. If the quantity (value on the right) is 1, I want to display the full shelf value.
I am currently using a SUBSTRING to get the 2 letters and a COUNT to get the quantity
The query I am using so far may seem complicated but here it is
SELECT DISTINCT SUBSTRING(location, 1, 2) AS ShelfNum,
COUNT(location) as Quantity
FROM warehouse_locations
WHERE unitId_unitId = 1
GROUP BY SUBSTRING(location, 1, 2)
ORDER BY ShelfNum asc
If I try to add the full location on the end if the quantity is 1, I get a group-by error
You can use a case expression to choose between max(name) and count(location) based on the result. You will need to convert the count(location) to the datatype that is returned by max(name).
Sql Server example:
select
substring(location, 1, 2) as ShelfNum
, case when count(location) = 1 then max(name)
else cast(count(location) as varchar(32))
end as Quantity
from warehouse_locations
where unitId_unitId = 1
group by substring(location, 1, 2)
order by ShelfNum asc
Also: you do not need to use distinct when you are using group by.
This would work.
SELECT CASE WHEN Quantity = 1
THEN location
ELSE ShelfNum END as ShelfNum
,Quantity
FROM (
SELECT DISTINCT SUBSTRING(location, 1, 2) AS ShelfNum,
location,
COUNT(location) as Quantity
FROM warehouse_locations
WHERE unitId_unitId = 1
GROUP BY SUBSTRING(location, 1, 2), location
)
ORDER BY ShelfNum asc
I am having a real problem trying to get a query with the data I need. I have tried a few methods without success. I can get the data with 4 separate queries, just can't get hem into 1 query. All data comes from 1 table. I will list as much info as I can.
My data looks like this. I have a customerID and 3 columns that record who has worked on the record for that customer as well as the assigned acct manager
RecID_Customer___CreatedBy____LastUser____AcctMan
1-------1374----------Bob Jones--------Mary Willis------Bob Jones
2-------1375----------Mary Willis------Bob Jones--------Bob Jones
3-------1376----------Jay Scott--------Mary Willis-------Mary Willis
4-------1377----------Jay Scott--------Mary Willis------Jay Scott
5-------1378----------Bob Jones--------Jay Scott--------Jay Scott
I want the query to return the following data. See below for a description of how each is obtained.
Employee___Created__Modified__Mod Own__Created Own
Bob Jones--------2-----------1---------------1----------------1
Mary Willis------1-----------2---------------1----------------0
Jay Scott--------2-----------1---------------1----------------1
Created = Counts the number of records created by each Employee
Modified = Number of records where the Employee is listed as Last User
(except where they created the record)
Mod Own = Number of records for each where the LastUser = Acctman
(account manager)
Created Own = Number of Records created by the employee where they are
the account manager for that customer
I can get each of these from a query, just need to somehow combine them:
Select CreatedBy, COUNT(CreatedBy) as Created
FROM [dbo].[Cust_REc] GROUP By CreatedBy
Select LastUser, COUNT(LastUser) as Modified
FROM [dbo].[Cust_REc] Where LastUser != CreatedBy GROUP By LastUser
Select AcctMan, COUNT(AcctMan) as CreatePort
FROM [dbo].[Cust_REc] Where AcctMan = CreatedBy GROUP By AcctMan
Select AcctMan, COUNT(AcctMan) as ModPort
FROM [dbo].[Cust_REc] Where AcctMan = LastUser AND NOT AcctMan = CreatedBy GROUP By AcctMan
Can someone see a way to do this? I may have to join the table to itself, but my attempts have not given me the correct data.
The following will give you the results you're looking for.
select
e.employee,
create_count=(select count(*) from customers c where c.createdby=e.employee),
mod_count=(select count(*) from customers c where c.lastmodifiedby=e.employee),
create_own_count=(select count(*) from customers c where c.createdby=e.employee and c.acctman=e.employee),
mod_own_count=(select count(*) from customers c where c.lastmodifiedby=e.employee and c.acctman=e.employee)
from (
select employee=createdby from customers
union
select employee=lastmodifiedby from customers
union
select employee=acctman from customers
) e
Note: there are other approaches that are more efficient than this but potentially far more complex as well. Specifically, I would bet there is a master Employee table somewhere that would prevent you from having to do the inline view just to get the list of names.
this seems pretty straight forward. Try this:
select a.employee,b.created,c.modified ....
from (select distinct created_by from data) as a
inner join
(select created_by,count(*) as created from data group by created_by) as b
on a.employee = b.created_by)
inner join ....
This highly inefficient query may be a rough start to what you are looking for. Once you validate the data then there are things you can do to tidy it up and make it more efficient.
Also, I don't think you need the DISTINCT on the UNION part because the UNION will return DISTINCT values unless UNION ALL is specified.
SELECT
Employees.EmployeeID,
Created =(SELECT COUNT(*) FROM Cust_REc WHERE Cust_REc.CreatedBy=Employees.EmployeeID),
Mopdified =(SELECT COUNT(*) FROM Cust_REc WHERE Cust_REc.LastUser=Employees.EmployeeID AND Cust_REc.CreateBy<>Employees.EmployeeID),
ModOwn =
CASE WHEN NOT Empoyees.IsManager THEN NULL ELSE
(SELECT COUNT(*) FROM Cust_REc WHERE AcctMan=Employees.EmployeeID)
END,
CreatedOwn=(SELECT COUNT(*) FROM Cust_REc WHERE AcctMan=Employees.EmployeeID AND CReatedBy=Employees.EMployeeID)
FROM
(
SELECT
EmployeeID,
IsManager=CASE WHEN EXISTS(SELECT AcctMan FROM CustRec WHERE AcctMan=EmployeeID)
FROM
(
SELECT DISTINCT
EmployeeID
FROM
(
SELECT EmployeeID=CreatedBy FROM Cust_Rec
UNION
SELECT EmployeeID=LastUser FROM Cust_Rec
UNION
SELECT EmployeeID=AcctMan FROM Cust_Rec
)AS Z
)AS Y
)
AS Employees
I had the same issue with the Modified column. All the other columns worked okay. DCR example would work well with the join on an employees table if you have it.
SELECT CreatedBy AS [Employee],
COUNT(CreatedBy) AS [Created],
--Couldn't get modified to pull the right results
SUM(CASE WHEN LastUser = AcctMan THEN 1 ELSE 0 END) [Mod Own],
SUM(CASE WHEN CreatedBy = AcctMan THEN 1 ELSE 0 END) [Created Own]
FROM Cust_Rec
GROUP BY CreatedBy
Using the AdventureWorks database, I need to produce a list of job titles and the amount of employees who are assigned to each of them. But that's not my concern.
When the OrganizationLevel is 2 or below, I need to make the Job Title field capitalized. However, I also need a condition that restricts job titles from being displayed when they're 3 or below. Can you please help me? Here is an (incorrect) attempt - I'm aware this is wrong, I've practically given up, but I'm hopeful it will help explain what I'm trying to achieve here.
SELECT distinct JobTitle, count(JobTitle) as CountOf from HumanResources.Employee
WHERE (OrganizationLevel < 3)
GROUP BY JobTitle
ELSE IF (OrganizationLevel < 2) select distinct UPPER(JobTitle);
SELECT
CASE
WHEN OrganizationLevel < 2 THEN JobTitle
ELSE UPPER(JobTitle)
END as JobTitle,
count(*) as CountOf
FROM HumanResources.Employee
WHERE OrganizationLevel < 3
GROUP BY
CASE
WHEN OrganizationLevel < 2 THEN JobTitle
ELSE UPPER(JobTitle)
END
I am writing a stored procedure, where I have a column called scale which stores the result from the radio button selected as 1/ 2/ 3/ 4 for each type of skill name.
Now, I want to see total number of people under each scale- 1 and 2 and 3 and 4 for a particular skillname1, skillname 2,..., skillname20.
Here is my table:
tblSkill:
ID | SkillName
and another table as:
tblskillMetrics:
ID | SkillID | EmployeeID | Scale
And here is the query am trying to write:
Create Procedure spGetSkillMetricsCount
As
Begin
SELECT
tblSkill.Name as skillname,
(select COUNT(EmployeeID) from tblSkillMetrics where tblSkillMetrics.Scale=1) AS NotAplicable,
(select COUNT(EmployeeID) from tblSkillMetrics where tblSkillMetrics.Scale=2 ) AS Beginner,
(select COUNT(EmployeeID) from tblSkillMetrics where tblSkillMetrics.Scale=3 ) AS Proficient,
(select COUNT(EmployeeID) from tblSkillMetrics where tblSkillMetrics.Scale=4 ) AS Expert
FROM
tblSkill
INNER JOIN
tblSkillMetrics ON tblSkillMetrics.SkillID = tblSkill.ID
GROUP BY
tblSkillMetrics.Scale, tblSkill.Name
ORDER BY
skillname DESC
END
By using this stored procedure, I am able to get the desired format in which I want the result but in the output for each : Not Applicable, Beginner, Proficient or Expert is same and it is sum of all the entries made in the table.
Please can someone suggest where am I going wrong.
Logically, you are grouping by two criteria, scale and skill name. However, if I understand it correctly, every row is supposed to represent a single skill name. Therefore, you should group by tblSkill.Name only. To get different counts for different scales in separate columns, you can use conditional aggregation, i.e. aggregation on an expression that (usually) involves a CASE construct. Here's how you could go about it:
SELECT
tblSkill.Name AS skillname,
COUNT(CASE tblSkillMetrics.Scale WHEN 1 THEN EmployeeID END) AS NotAplicable,
COUNT(CASE tblSkillMetrics.Scale WHEN 2 THEN EmployeeID END) AS Beginner,
COUNT(CASE tblSkillMetrics.Scale WHEN 3 THEN EmployeeID END) AS Proficient,
COUNT(CASE tblSkillMetrics.Scale WHEN 4 THEN EmployeeID END) AS Expert
FROM
tblSkill
INNER JOIN
tblSkillMetrics ON tblSkillMetrics.SkillID = tblSkill.ID
GROUP BY
tblSkill.Name
ORDER BY
skillname DESC
;
Note that there's a special syntax for this kind of queries. It employs the PIVOT keyword, as what you get is essentially a grouped result set pivoted on one of the grouping criteria, scale in this case. This is how the same could be achieved with PIVOT:
SELECT
skillname,
[1] AS NotAplicable,
[2] AS Beginner,
[3] AS Proficient,
[4] AS Expert
FROM (
SELECT
tblSkill.Name AS skillname,
tblSkillMetrics.Scale,
EmployeeID
FROM
tblSkill
INNER JOIN
tblSkillMetrics ON tblSkillMetrics.SkillID = tblSkill.ID
) s
PIVOT (
COUNT(EmployeeID) FOR Scale IN ([1], [2], [3], [4])
) p
;
Basically, PIVOT implies grouping. All columns but one in the source dataset are grouping criteria, namely every one of them that is not used as an argument of an aggregate function in the PIVOT clause is a grouping criterion. One of them is also assigned to be the one the results are pivoted on. (Again, in this case it is scale.)
Because grouping is implicit, a derived table is used to avoid grouping by more criteria than necessary. Values of Scale become names of new columns that the PIVOT clause produces. (That is why they are delimited with square brackets when listed in PIVOT: they are not IDs in that context but identifiers delimited as required by Transact-SQL syntax.)
A case construct instead of all those subqueries might work.
select tblSkill.name skillname
, case when tblSkillMetrics = 1 then 'Not Applicable'
etc
else 'Expert' end level
, count(employeeid) records
from tblSkill join tblSkillMetrics
on tblSkillMetrics.SkillID = tblSkill.ID
group by tblSkill.name
, case when tblSkillMetrics = 1 then 'Not Applicable'
etc
else 'Expert' end level
order by skillname desc
You can use something like this:
SELECT sum(case when tblskillmetrics.scale = 2 then 1 else 0 end) Beginner,
sum(case when tblskillmetrics.Scale=3 then 1 else 0 end)Proficient,
SUM(case when tblSkillMetrics.Scale=4 then 1 else 0 end)Expert,
tblSkillGroup.ID AS GroupID,tblSkillGroup.Name AS GroupName,
tblSkill.ID AS SkillID
, tblSkill.Name AS SkillName
FROM tblSkill INNER JOIN tblSkillMetrics
ON tblSkillMetrics.SkillID=tblSkill.ID
ORDER BY GroupName DESC