PowerBI / SQL Query to verify records - sql

I am working on a PowerBI report that is grabbing information from SQL and I cannot find a way to solve my problem using PowerBI or how to write the required code. My first table, Certifications, includes a list of certifications and required trainings that must be obtained in order to have an active certification.
My second table, UserCertifications, includes a list of UserIDs, certifications, and the trainings associated with a certification.
How can I write a SQL code or PowerBI measure to tell if a user has all required trainings for a certification? ie, if UserID 1 has the A certification, how can I verify that they have the TrainingIDs of 1, 10, and 150 associated with it?
Certifications:
CertificationsTable
UserCertifications:
UserCertificationsTable

This is a DAX pattern to test if contains at least some values.
| Certifications |
|----------------|------------|
| Certification | TrainingID |
|----------------|------------|
| A | 1 |
| A | 10 |
| A | 150 |
| B | 7 |
| B | 9 |
| UserCertifications |
|--------------------|---------------|----------|
| UserID | Certification | Training |
|--------------------|---------------|----------|
| 1 | A | 1 |
| 1 | A | 10 |
| 1 | A | 300 |
| 2 | A | 150 |
| 2 | B | 9 |
| 2 | B | 90 |
| 3 | A | 7 |
| 4 | A | 1 |
| 4 | A | 10 |
| 4 | A | 150 |
| 4 | A | 1000 |
In the above scenario, DAX needs to find out if the mandatory trainings (Certifications[TrainingID]) by Certifications[Certification] is completed by
UserCertifications[UserID ]&&UserCertifications[Certifications] partition.
In the above scenario, DAX should only return true for UserCertifications[UserID ]=4 as it is the only User that completed at least all the mandatory trainings.
The way to achieve this is through the following measure
areAllMandatoryTrainingCompleted =
VAR _alreadyCompleted =
CONCATENATEX (
UserCertifications,
UserCertifications[Training],
"-",
UserCertifications[Training]
) // what is completed in the fact Table; the fourth argument is very important as it decides the sort order
VAR _0 =
MAX ( UserCertifications[Certification] )
VAR _supposedToComplete =
CONCATENATEX (
FILTER ( Certifications, Certifications[Certification] = _0 ),
Certifications[TrainingID],
"-",
Certifications[TrainingID]
) // what is comeleted in the training Table; the fourth argument is very important as it decides the sort order
VAR _isMandatoryTrainingCompleted =
CONTAINSSTRING ( _alreadyCompleted, _supposedToComplete ) // CONTAINSSTRING (<Within Text>,<Search Text>); return true false
RETURN
_isMandatoryTrainingCompleted

Related

Get deleted users details if userid refrence to some table

I'm bit confused with this problem, I have following table called Member and its structure as follows,
+----------+------+-------------+
| MemberID | Name | ActiveState |
+----------+------+-------------+
| 1 | PAUL | 1 |
+----------+------+-------------+
| 2 | JHON | 1 |
+----------+------+-------------+
| 3 | AMBE | 0 |
+----------+------+-------------+
| 4 | NISH | 1 |
+----------+------+-------------+
And I have another table called ServiceProvided. and its structure as follows. All the member provided data will be saved in this table.
+--------------+-------------+------------+
| ServiceProID | Fkserviceid | FkMemberID |
+--------------+-------------+------------+
| 1 | S1 | 1 |
+--------------+-------------+------------+
| 2 | S2 | 1 |
+--------------+-------------+------------+
| 3 | S1 | 2 |
+--------------+-------------+------------+
| 4 | S3 | 2 |
+--------------+-------------+------------+
Application can soft delete members by changing their active state to 0. I need to get all the ActiveState = 1members data and need to get only if that member has provided any service in the past, should his data be retrieved even if he is deleted. How can I do it.
Expected output is,
ActiveState = 1 and ActiveState = 0 members who has only provided any service in the past
SELECT m.*
FROM Member m
WHERE m.ActiveState = 1
UNION
SELECT m.*
FROM Member m
INNER JOIN ServiceProvided s ON m.MemberId = s.FkMemberId
WHERE m.ActiveState = 0;
The easiest way to achieve this is with UNION.
The INNER JOIN on the deleted Member query assures that you will not retrieve a Member who lacks entries in ServiceProvided.

How to add data or change schema to production database

I am new to working with databases and I want to make sure I understand the best way to add or remove data from a database without making a mess of any related data.
Here is a scenario I am working with:
I have a Tags table, with an Identity ID column. The Tags can be selected via the web application to categorize stories that are submitted by a user. When the database was first seeded; like tags were seeded in order together. As you can see all the Campuses (cities) were 1-4, the Colleges (subjects) are 5-7, and Populations are 8-11.
If this database is live in production and the client wants to add a new Campus (City) tag, what is the best way to do this?
All the other city tags are sort of organized at the top, it seems like the only option is to insert any new tags at to bottom of the table, where they will end up taking whatever the next ID available is. I suppose this is fine because the Display category column will allow us to know which categories these new tags actually belong to.
Is this typical? Is there better ways to set up the database or handle this situation such that everything remains more organized?
Thank you
+----+------------------+---------------+-----------------+--------------+--------+----------+
| ID | DisplayName | DisplayDetail | DisplayCategory | DisplayOrder | Active | ParentID |
+----+------------------+---------------+-----------------+--------------+--------+----------+
| 1 | Albany | NULL | 1 | 0 | 1 | NULL |
| 2 | Buffalo | NULL | 1 | 1 | 1 | NULL |
| 3 | New York City | NULL | 1 | 2 | 1 | NULL |
| 4 | Syracuse | NULL | 1 | 3 | 1 | NULL |
| 5 | Business | NULL | 2 | 0 | 1 | NULL |
| 6 | Dentistry | NULL | 2 | 1 | 1 | NULL |
| 7 | Law | NULL | 2 | 2 | 1 | NULL |
| 8 | Student-Athletes | NULL | 3 | 0 | 1 | NULL |
| 9 | Alumni | NULL | 3 | 1 | 1 | NULL |
| 10 | Faculty | NULL | 3 | 2 | 1 | NULL |
| 11 | Staff | NULL | 3 | 3 | 1 | NULL |
+----+------------------+---------------+-----------------+--------------+--------+----------+
The terms "top" and "bottom" which you use aren't really applicable. "Albany" isn't at the "Top" of the table - it's merely at the top of the specific view you see when you query the table without specifying a meaningful sort order. It defaults to a sort order based on the Id or an internal ROWID parameter, which isn't the logical way to show this data.
Data in the table isn't inherently ordered. If you want to view your tags organized by their category, simply order your query by DisplayCategory (and probably by DisplayOrder afterwards), and you'll see your data properly organized. You can even create a persistent View that sorts it that way for your convenience.

SQLite3 select last event by user

I have the following table 'events'.
| id | event_type | by_user | asset | time |
| 1 | owner | a | 10 | 1111111111 |
| 2 | updated | b | 20 | 1111111112 |
| 3 | owner | a | 30 | 1111111113 |
| 4 | owner | c | 20 | 1111111114 |
| 5 | updated | a | 10 | 1111111115 |
| 6 | owner | a | 20 | 1111111118 |
I would like to select the assets where user 'a' was the last user
with an 'owner' event_type. So in this example the id's 1, 3 and 6 (the
assets 10, 20 and 30 are owned by user 'a').
Basically, based on the events, I want to find the assests owned by user 'a'.
This is what correlated subqueries are for:
SELECT * FROM events e
WHERE event_type='owner'
AND time=(SELECT MAX(e_inner.time) FROM events e_inner
WHERE e_inner.asset=e.asset AND e_inner.event_type='owner')
Will give you the event that is "for each asset, show the last ownership event". If you want it for specific assets or specific owners, just add an appropriate WHERE clause
Your question is ripe for breakage if you aren't guaranteeing uniqueness of {time, event_type, asset}. This will return all n rows if you have n users being assigned ownership at the exact same time.

Update the first and last records only amongst many duplicate records

I have a table in Access named Spells which holds patient spells (where a patient has a spell within a hospital). It's structure is as below:
| ID | SpellID | MultipleSpell | FirstSpell | LastSpell |
|----|---------|---------------|------------|-----------|
| 1 | 1 | False | | |
| 2 | 2 | True | | |
| 3 | 2 | True | | |
| 4 | 3 | False | | |
| 5 | 4 | False | | |
| 6 | 5 | True | | |
| 7 | 5 | True | | |
| 8 | 5 | True | | |
The MultipleSpell column indicates that there are multiple occurrences of the spell within the table.
I'd like to run query which would update the FirstSpell column to True for records with the IDs of 1,2,4,5,6. So basically, where a Spell is the first one in the table, it should be marked, in the FirstSpell column.
I would also then like to update the LastSpell column to True for records with the IDs of 1,3,4,5,8.
The reasoning for this (if you're interested) is that the table links to a separate table containing the name of wards. It would be useful to link to this other table and indicate whether the ward is the admitting ward (FirstSpell) or the discharging ward (LastSpell)
You can update the first using:
update spells
set firstspell = 1
where id = (select min(id)
from spells as s2
where spells.spellid = s2.spellid
);
Similar logic (using max()) can be used for the last spell.

SQL query for many-to-many self-join

I have a database table that has a companion many-to-many self-join table alongside it. The primary table is part and the other table is alternate_part (basically, alternate parts are identical to their main part with different #s). Every record in the alternate_part table is also in the part table. To illustrate:
`part`
| part_id | part_number | description |
|---------|-------------|-------------|
| 1 | 00001 | wheel |
| 2 | 00002 | tire |
| 3 | 00003 | window |
| 4 | 00004 | seat |
| 5 | 00005 | wheel |
| 6 | 00006 | tire |
| 7 | 00007 | window |
| 8 | 00008 | seat |
| 9 | 00009 | wheel |
| 10 | 00010 | tire |
| 11 | 00011 | window |
| 12 | 00012 | seat |
`alternate_part`
| main_part_id | alt_part_id |
|--------------|-------------|
| 1 | 5 | // Wheel
| 5 | 1 | // |
| 5 | 9 | // |
| 9 | 5 | // |
| 2 | 6 | // Tire
| 6 | 2 | // |
| ... | ... | // |
I am trying to produce a simple SQL query that will give me a list of all alternates for a main part. The tricky part is: some alternates are only listed as alternates of alternates, it is not guaranteed that every viable alternate for a part is listed as a direct alternate. e.g., if 'Part 3' is an alternate of 'Part 2' which is an alternate of 'Part 1', then Part 3 is an alternate of Part 1 (even if the alternate_part table doesn't list a direct link). The reverse is also true (Part 1 is an alternate of Part 3).
Basically, right now I'm pulling alternates and iterating through them
SELECT p.*, ap.*
FROM part p
INNER JOIN alternate_part ap ON p.part_id = ap.main_part_id
And then going back and doing the same again on those alternates. But, I think there's got to be a better way.
The SQL query I'm looking for will basically give me:
| part_id | alt_part_id |
|---------|-------------|
| 1 | 5 |
| 1 | 9 |
For part_id = 1, even when 1 & 9 are not explicitly linked in the alternates table.
Note: I have no control whatever over the structure of the DB, it is a distributed software solution.
Note 2: It is an Oracle platform, if that affects syntax.
You have to create hierarchical tree , probably you have to use connect by prior , nocycle query
something like this
select distinct p.part_id,p.part_number,p.description,c.main_part_id
from part p
left join (
select main_part_id,connect_by_root(main_part_id) real_part_id
from alternate_part
connect by NOCYCLE prior main_part_id = alternate_part_id
) c
on p.part_id = c.real_part_id and p.part_id != c.main_part_id
order by p.part_id
You can read full documentation about Hierarchical queries at http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries003.htm