I have an Oracle table OBJECTS with columns Id, parent id, object_type and name.
I have real time object types as Groups, Accounts and Services. They are hierarchical in the same order. That means, Groups contains Accounts and Accounts contains Services. So, service.parent_id will refer to account.object_id and account.parent_id will refer to group.object_id within the same table.
Criteria fields for selecting data must be passed as parameters to the query. Now, if the User provides a Group ID, then the query must fetch all Services that are belonged to all the Accounts within that group.
Similarly, if the user provides ID for Account, the query must return all the Services under the Account.
I have written the following query, but it doesn't work exactly I need. Can someone help me fix it?
WITH services AS
(SELECT nco.object_id,
nco.parent_id,
nco.object_type_id,
nco.name
FROM objects nco
WHERE nco.object_type_id = 9146522450013755288 ),
accounts AS
(SELECT nco.object_id,
nco.parent_id,
nco.name
FROM objects nco,
services ss
WHERE nco.object_type_id=9145485031713653586
AND nco.object_id = ss.parent_id ),
groups AS
(SELECT nco.object_id,
nco.parent_id,
nco.name
FROM objects nco,
accounts sa
WHERE nco.object_id = sa.parent_id
AND nco.object_type_id = 9146513648413722258 )
SELECT *
FROM services ss,
accounts sa,
groups sg
WHERE ss.object_id IN (#Services#)
OR sa.object_id IN (#Accounts#)
OR sg.object_id IN (#Groups#)
Input is passed as Macros using (##) and there can be multiple Group ID's, Account ID's and Service ID's passed. object_type_id is a column which will identify what type of object it is. For example, 9146513648413722258 refers to Services, 9145485031713653586 refers to Accounts etc.
In your case, an inner join makes more sense that a full join ,, therefore
SELECT services.*
FROM objects groups
INNER JOIN objects accounts
ON groups.object_type_id=9146522450013755288
AND accounts.object_type_id=9146513648413722258
AND accounts.parent_id=groups.object_id
INNER JOIN objects services
ON services.object_type_id=9145485031713653586
AND services.parent_id=accounts.object_id
WHERE services.object_id IN (#Services#)
OR accounts.object_id IN (#Accounts#)
OR groups.object_id IN (#Groups#)
The query joins the services, accounts and groups table (implicitly from the objects table) using the parent_id and then filter out the result.
Related
There are two tables, an account table and a tenant table. An account has multiple tenants. I want to find a list of accounts.
For eg, An account XXX can have multiple tenants - sandbox, implementation, development etc.
I want to extract a list of accounts without an implementation tenant, using SQL.
I tried the something like this :
select a.accountname, t.tenanttype,
from account a
inner join tenant t
using (accountid)
WHERE
t.tenanttype NOT IN ('Implementation%');
I get all accounts with their tenant types, but it just filters out the Implementation tenant , even though it exists.
Eg. An account XXX has 4 tenants, Sandbox. Dev, Implementation and Preview.
My code returns the account XXX, but with just three values - Sandbox, Dev, and Preview.
I want to get a list of accounts that don't have the Implementation tenant AT ALL.
Based on your final statement it sounds like you need to use not exists, does the following work for you?
select a.accountname, t.tenanttype
from account a
join tenant t on a.accountid = t.accountid
where not exists (
select * from tenant t2
where t2.accountid = t.accountid and t2.tenanttype like 'Implementation%'
);
I have system that has different levels for users depends on what is assigned upon their account was created. So there is four different levels 1,2,3 and 4. First level have full access and then each level below narrows down to data access. So once user logged in I should get records from my Permissions table. One account can have more than one record in permissions table. Here is example:
AccountID UserName AccessLevel AccessType State City Building
FB3064A7 jfakey S F 05 NULL NULL
FB3064A7 jfakey S F 07 NULL NULL
You can see there is AccessLevel column that can have Region R, State S, City C or Building B. If user has assigned Region access there should be only one record. If there is any other access level (S,C or B) then user can have multiple records. Example above has State level. There is two different states assigned to that account and my query will return two rows. I'm wondering should I split this in two separate queries or stick with once query and merge the rows? I'm wondering what would be more efficient since this is login page there is a lot of hits. Here is example of my query:
SELECT A.AccountID, A.UserName,
P.AccessLevel, P.AccessType, P.State, P.City, P.Building
FROM Accounts AS A WITH (NOLOCK)
INNER JOIN Permissions AS P WITH (NOLOCK)
ON A.AccountID = P.AccountID
WHERE UserName = 'jfakey'
Query above is what I have now and that returns two rows. If anyone have suggestion on what is the best approach please let me know.
I have a table with list of Users that has two columns Username and FullName.
I have a table with list of Applications that has two columns Id and Name.
I have a table with a list of Applications that Users have, UserApplications, it has two columns, Username and ApplicationId.
The UserApplications table defines that applications a user has on their computer.
On a project where users are awaiting for applications to be upgraded, how do I get a report that shows a list of applications that would satisfy the most users. I need to generate a report of n (1 to 10) applications. e.g. if resources are available to migrate n applications, which n applications would satisfy most amount of users so the remaining applications can be done sequentially.
Also need to generate a list of applications that would satisfy the most users immediately if migrated in order.
Dialect is MS SQL
This is a re-phrasing of the query given by Dick Appel, and I break it down for benefit of your understanding:
SELECT
ApplicationId, count(*) as AppCount
FROM
UserApplications
GROUP BY
ApplicationID
Hopefully you can easily see that this query will give a unique list of application ids, and the count of the number of users that have that app
Now we need some more detail about the application. We don't care about any user detail. We take that query above and turn it io a subquery (actually we don't have to but it's easier to see what goes on if we do)
SELECT ApplicationName, AppCount
FROM
(
SELECT
ApplicationId, count(*) as AppCount
FROM
UserApplications
GROUP BY
ApplicationID
) appcounts
INNER JOIN
Applications
ON
app counts.ApplicationID = Applications.ApplicationID
ORDER BY AppCount DESC
The subject that does the counts per ID is joined to the applications table that gives detail on each ID. It is ordered descending by the count of apps
After this point we really need to know what database is in use to limit the results to 10, as different database have different syntax. Dick used sql server syntax. Oracle or MySQL would have LIMIT 10 in the outer query, and the subquery would possibly need to be the one that was ordered
You could go a couple of ways here, but somthing like this (don't know which dialect you would be using ) -- basically create a subquery that just produces a list of all applications that have users and the number of users they have ('ApplicationUserCount') and order that with the outer query in descending order.
SELECT TOP 10 Application, UserCount
FROM (SELECT A.ApplicationName as Application, COUNT(*) as UserCount
FROM Applications A
INNER JOIN UserApplications UA ON (A.ApplicationId = UA.ApplicationId)
GROUP BY A.ApplicationName ) ApplicationUserCount
ORDER BY UserCount DESC
Well I am designing a domain model and data mapper system for my site. The system has different kind of user domain objects, with the base class for users with child classes for admins, mods and banned users. Every domain object uses data from a table called 'users', while the child classes have an additional table to store admin/mod/banned information. The user type is determined by a column in the table 'users' called 'userlevel', its value is 3 for admins, 2 for mods, 1 for registered users and -1 for banned users.
Now it comes a problem when I work on a members list feature for my site, since the members list is supposed to load all users from the database(with pagination, but lets not worry about this now). The issue is that I want to load the data from both the base user table and additional admin/mod/banned table. As you see, the registered users do not have additional table to store extra data, while for admin/mod/banned users the table is different. Moreover, the columns in these tables are also different.
So How am I supposed to handle this situation using SQL queries? I know I can simply just select from the base user table and then use multiple queries to load additional data if the user level is found to be a given value, but this is a bad idea since it will results in n+1 queries for n admins/mods/banned users, a very expensive trip to database. What else am I supposed to do? Please help.
If you want to query all usertypes with one query you will have to have the columns from all tables in your result-table, several of them filled with null-values.
To get them filled with data use a left-join like this:
SELECT *
FROM userdata u
LEFT OUTER JOIN admindata a
ON ( u.userid = a.userid
AND u.usertype = 3 )
LEFT OUTER JOIN moddata m
ON ( u.userid = m.userid
AND u.usertype = 2 )
LEFT OUTER JOIN banneddata b
ON ( u.userid = b.userid
AND u.usertype = -1 )
WHERE...
You could probably drop the usertype-condition, since there should only be data in one of the joined tables, but you never know...
Then your program-code will have the job to pick the correct columns based on the usertype.
P.S.: Not that select * is only for sake of simplicity, in real code better list all of the column-names...
While is totally fine having this hierarchy in your domain classes, I would suggest changing the approach in your database. Otherwise your queries are going to be very complex and slow.
You can have just another table called e.g. users_additional_info with the mix of the columns that you need for all your user types. Then you can do
SELECT * FROM users
LEFT JOIN users_additional_info ON users.id = users_additional_info.user_id
to get all the information in a single simple query. Believe me or not, this approach will save you a lots of headaches in the future when your tables start to grow or you decide to add another type of user.
I have one database that contains all of user information including name. Then there is a second database that contains notes from the users and it contains the #id but not the name. The query i am doing to retrieve user notes doesn't have name so all its doing is showing the notes, then right under it i am doing another query to retrieve the name from the first database using the common #id. But it won't show.
Is there a way I can do this query in one? Please help. Thanks.
Use:
SELECT u.name,
n.*
FROM DB2.NOTES n
LEFT JOIN DB1.USERS u ON n.id = u.id
ORDER BY u.name
Assuming the connection credentials has access to both databases, you prefix the database name in front of the table name and separate with a period.
The LEFT JOIN will show both users, and notes without users associated. Here's a good primer on JOINs.
You might need to show your code, but you can write queries against two databases (or schemas) on the same host, just qualify the table names with the database name, e.g.
SELECT db1.user.id, db1.user.name, db2.userinfo.notes
FROM db1.user
INNER JOIN db2.userinfo ON(db1.user.id=db2.userinfo.id)
The credentials you are connecting with must have access to both databases for this to work of course.