sqlite INNER JOIN only if data - sql

Example with tables :
Promotion(idPromo, nameUser)
Company(idCompany, nameCompany)
PromoCompany(idPromo, idCompany)
I try to get with only one query, all promotions who have a company (idCompany = 1 for example) OR who have 0 company.
To describe :
PromoCompany is a restriction table... if data exist for a promotion, promotion is valable for only this companies, if no data, promotion valable for all companies.
Example :
Promo[{
idPromo:1
namePromo:"promo test"
},
{
idPromo:2
namePromo:"promo test 2"
}]
Company[{
idCompany:10
nameCompany:"CompanyPloof"
},{
idCompany:12
nameCompany:"CompanyPaf"
}
]
PromoCompany[{
idPromo:1
idCompany:10
},{
idPromo:1
idCompany:12
}
]
If my company is CompanyPloof, promos are idPromo 1 et 2
If my company is CompanyPaf, promos are idPromo 2 (because not restricted)

Hmmm . . . this sounds like two conditions:
select p.*
from promotions p
where exists (select 1 from promocompany pc where pc.idpromo = p.idpromo and p.idcompany = 1) or
not exists (select 1 from promocompany pc where pc.idpromo = p.idpromo);
I would suggest a small change to your data model. Add a flag in promotions that says whether the promotion is available for all companies or if it is restricted. Having to search through a table is a little awkward -- and potentially confusing. Adding one row to the table could invalidate a promotion for everyone else.

Related

Sql Left or Right Join One To Many Pagination

I have one main table and join other tables via left outer or right outer outer join.One row of main table have over 30 row in join query as result. And I try pagination. But the problem is I can not know how many rows will it return for one main table row result.
Example :
Main table first row result is in my query 40 rows.
Main table second row result is 120 row.
Problem(Question) UPDATE:
For pagination I need give the pagesize the count of select result. But I can not know the right count for my select result. Example I give page no 1 and pagesize 50, because of this I cant get the right result.I need give the right pagesize for my main table top 10 result. Maybe for top 10 row will the result row count 200 but my page size is 50 this is the problem.
I am using Sql 2014. I need it for my ASP.NET project but is not important.
Sample UPDATE :
it is like searching an hotel for booking. Your main table is hotel table. And the another things are (mediatable)images, (mediatable)videos, (placetable)location and maybe (commenttable)comments they are more than one rows and have one to many relationship for the hotel. For one hotel the result will like 100, 50 or 10 rows for this all info. And I am trying to paginate this hotels result. I need get always 20 or 30 or 50 hotels for performance in my project.
Sample Query UPDATE :
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Hotel Table :
HotelId HotelName
1 Barcelona
2 Berlin
Media Table :
MediaID MediaUrl HotelId
1 www.xxx.com 1
2 www.xxx.com 1
3 www.xxx.com 1
4 www.xxx.com 1
Location Table :
LocationId Adress HotelId
1 xyz, Berlin 1
2 xyz, Nice 1
3 xyz, Sevilla 1
4 xyz, Barcelona 1
Comment Table :
CommentId Comment HotelId
1 you are cool 1
2 you are great 1
3 you are bad 1
4 hmm you are okey 1
This is only sample! I have 9999999 hotels in my database. Imagine a hotel maybe it has 100 images maybe zero. I can not know this. And I need get 20 hotels in my result(pagination). But 20 hotels means 1000 rows maybe or 100 rows.
First, your query is poorly written for readability flow / relationship of tables. I have updated and indented to try and show how/where tables related in hierarchical relativity.
You also want to paginate, lets get back to that. Are you intending to show every record as a possible item, or did you intend to show a "parent" level set of data... Ex so you have only one instance per Media, Per User, or whatever, then once that entry is selected you would show details for that one entity? if so, I would do a query of DISTINCT at the top-level, or at least grab the few columns with a count(*) of child records it has to show at the next level.
Also, mixing inner, left and right joins can be confusing. Typically a right-join means you want the records from the right-table of the join. Could this be rewritten to have all required tables to the left, and non-required being left-join TO the secondary table?
Clarification of all these relationships would definitely help along with the context you are trying to get out of the pagination. I'll check for comments, but if lengthy, I would edit your original post question with additional details vs a long comment.
Here is my SOMEWHAT clarified query rewritten to what I THINK the relationships are within your database. Notice my indentations showing where table A -> B -> C -> D for readability. All of these are (INNER) JOINs indicating they all must have a match between all respective tables. If some things are NOT always there, they would be changed to LEFT JOINs
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Readability of a query is a BIG help for yourself, and/or anyone assisting or following you. By not having the "on" clauses near the corresponding joins can be very confusing to follow.
Also, which is your PRIMARY table where the rest are lookup reference tables.
ADDITION PER COMMENT
Ok, so I updated a query which appears to have no context to the sample data and what you want in your post. That said, I would start with a list of hotels only and a count(*) of things per hotel so you can give SOME indication of how much stuff you have in detail. Something like
select
H.HotelID,
H.HotelName,
coalesce( MedSum.recs, 0 ) as MediaItems,
coalesce( LocSum.recs, 0 ) as NumberOfLocations,
coalesce( ComSum.recs, 0 ) as NumberOfLocations
from
Hotel H
LEFT JOIN
( select M.HotelID,
count(*) recs
from Media M
group by M.HotelID ) MedSum
on H.HotelID = MedSum.HotelID
LEFT JOIN
( select L.HotelID,
count(*) recs
from Location L
group by L.HotelID ) LocSum
on H.HotelID = LocSum.HotelID
LEFT JOIN
( select C.HotelID,
count(*) recs
from Comment C
group by C.HotelID ) ComSum
on H.HotelID = ComSum.HotelID
order by
H.HotelName
--- apply any limit per pagination
Now this will return every hotel at a top-level and the total count of things per the hotel per the individual counts which may or not exist hence each sub-check is a LEFT-JOIN. Expose a page of 20 different hotels. Now, as soon as one person picks a single hotel, you can then drill-into the locations, media and comments per that one hotel.
Now, although this COULD work, having to do these counts on an every-time query might get very time consuming. You might want to add counter columns to your main hotel table representing such counts as being performed here. Then, via some nightly process, you could re-update the counts ONCE to get them primed across all history, then update counts only for those hotels that have new activity since entered the date prior. Not like you are going to have 1,000,000 posts of new images, new locations, new comments in a day, but of 22,000, then those are the only hotel records you would re-update counts for. Each incremental cycle would be short based on only the newest entries added. For the web, having some pre-aggregate counts, sums, etc is a big time saver where practical.

Joining SQL statements Atrium Syntess Firebird DB

I'm trying to get (one or multiple) number lines (PROGCODE) that are attached to an OBJECT (i.e. a building) that is connected to a Relation which in turn has a GC_ID (relation unique ID). I need all the buildings & progcodes connected to a relation ID in a firebird 2.5 database generated by my companies ERP system.
I can look through all the tables in the firebird database and run select queries on them.I like to think I have the join statement syntax down and I know how to find the unique ID belonging to a relation, unfortunately I'm unsure how I can find the correct table that houses the information I seek.
The table I think this data is in has the following fields:
GC_ID, DEVICE_GC_ID, USER_GC_ID, CODE, DESCRIPTION.
However when I query it using
select GC_ID, DEVICE_GC_ID, USER_GC_ID, CODE, DESCRIPTION
from AT_PROGCODE A
Then I get a description of the fields I'm trying to query.
i.e.
| GC_ ID : 100005 | DEVICE_GC_ID : 100174 | USER_GC_ID : 1000073 | DESCRIPTION: >description of what I'm trying to query< |
Can anyone shed some insight how I should handle this?
Update 7-09-2017
I spoke with the ERP consultant and was told the tables I needed (if anyone reading this is using syntess Atrium; the AT_BRENT table holds a description of all the tables.)
However, I've run into a new problem; the data I get from my sql query keeps streaming (it seems to never end with me stopping the script at 90 mil loops and the ERP program crashing if I ask for a count).
select A.GC_OMSCHRIJVING Bedrijf, A.GC_CODE ,M.GC_OMSCHRIJVING Werktitel,
M.TELEFOON1, M.TELEFOON2, M.MOBIEL, M.EMAIL,
M.URL, M.DOORKIES_NR, M.WERKLOCATIE, M.EMAIL_INTERN
from AT_MEDEW M , AT_RELATIE A
JOIN AT_MEDEW ON A.GC_ID = M.GC_ID
WHERE M.TELEFOON1 <> '' OR M.TELEFOON2 <> '' OR M.MOBIEL <> ''
Any ideas on what's the cause for my latest peril?
First I had to find the AT_BRENT table which holds all the descriptions for tables in Syntess Atrium
Then I was using a CROSS JOIN (as pointed out by https://stackoverflow.com/users/696808/bacon-bits )
I ended up using
select A.GC_OMSCHRIJVING Bedrijf, A.GC_CODE ,M.GC_OMSCHRIJVING Werktitel,
M.TELEFOON1, M.TELEFOON2, M.MOBIEL, M.EMAIL,
M.URL, M.DOORKIES_NR, M.WERKLOCATIE, M.EMAIL_INTERN
from AT_MEDEW M
JOIN AT_RELATIE A ON A.GC_ID = M.GC_ID
WHERE M.TELEFOON1 <> '' OR M.TELEFOON2 <> '' OR M.MOBIEL <> ''
Thank you all who helped.

need the sum of sub sql select but need variables within the sub select

I'm building an SQL QUERY to an existing software (Atlassian Jira) and am not able to make any changes to the database.
We do have several Issues within Jira (table: jiraissue) which have a 0 to n worklog entries in a separate table (table: worklog). Each worklog has also an userid of the user which logged the work and the user is member of one ore more usergroups. Each of these Issues (table: jiraissue) is linked to another issue (within another jira project, but this is - I assume - not relevant for non jira experts) which corespondents as the "cost unit".
means we want to know how many work is logged on each "cost unit". therefore we need to have an query which returns all "cost unit's" and the time logged per usergroup on the linked issues. the last point is, that the "cost unit's" are market with an component to know which "cost unit's" belong together. therefore to display only the "cost unit's" which are relevant to the report-user the query is using the component for select this.
what I found out so far works quite well, but returns as many rows for the "cost unit" as there are linked issues, but I need the sum of all linked issues.
I somehow should be able to sum all the results from the subqueries, but these seems not to be possible. I also tried to work with the subselect statements after FROM, but then I'm not able to use jiraissue.id.
here is my actual query:
SELECT
myktr.pkey,
myktr.summary,
sum(worklog_dev),
(SELECT
sum(worklog.timeworked)
from
worklog
WHERE worklog.issueid = jiraissue.id
AND worklog.author IN
(SELECT
child_name
FROM
CWD_MEMBERSHIP
where lower_parent_name = 'jira-team-sdqm')) AS worklog_sdqm,
(SELECT
sum(worklog.timeworked)
from
worklog
WHERE worklog.issueid = jiraissue.id
AND worklog.author IN
(SELECT
child_name
FROM
CWD_MEMBERSHIP
where lower_parent_name = 'jira-productowner')) AS worklog_pm
FROM
component,
nodeassociation,
jiraissue AS myktr
INNER JOIN issuelink
ON (issuelink.source = myktr.id)
INNER JOIN jiraissue
ON (
issuelink.destination = jiraissue.id
),
(SELECT
sum(worklog.timeworked) AS worklog_dev
FROM
worklog
WHERE worklog.issueid = jiraissue.id
AND worklog.author IN
(SELECT
child_name
FROM
CWD_MEMBERSHIP
where lower_parent_name = 'jira-developers')) AS worklog_dev_table
WHERE myktr.pkey IN
(SELECT
jiraissue.pkey
from
jiraissue,
project
WHERE project.id = jiraissue.project
AND project.pkey = 'KTR')
AND component.ID = nodeassociation.SINK_NODE_ID
and myktr.id = nodeassociation.SOURCE_NODE_ID
and nodeassociation.ASSOCIATION_TYPE = 'IssueComponent'
and component.cname = 'Project-Component' ;
do you have any suggestions to me?
fyi: we are working with postgreSQL.
best regards,
stefan
For your aggregation to work correctly, you will need to use the GROUP BY-clause in your main select:
...
GROUP BY component
...

PL SQL Pivot Table VS Custom Json solution

I'm at a point within one of my Oracle APEX projects where I need to implement different levels of security for specific individuals for specific applications.
To start, I created a cartesian containing the information from the user table, the app table, and the role table.
It looks like this:
SELECT
A.user_id, B.app_id, C.role_id
FROM user A, app B, role C
ORDER BY A.user_id ASC, B.app_id ASC, C.role_id ASC
This allows me to return EVERY combination of user, app, and role. w/o using a where clause it returns over 303k rows. currently almost 500 users, 6 roles, and over 100 apps.
when I select from this view for a specific user its returning in approximately 10 ms which is acceptable.
Now, I also have a vw that stores each user's app/role assignment. I've joined this table to the cartesian in the following fashion.
SELECT
A.*,
DECODE(B.app_right_id, null, 0, 1) AS user_access
FROM
vw_user_app_role A -- My cartesian view
LEFT JOIN vw_tbl_user_app_role B
ON A.user_id = B.user_id
AND A.app_id = B.app_id
AND A.role_id = B.role_id
This returns a very usable set of data that resembles
user_id app_id role_id user_access
50 5 1 0
50 10 2 1
50 15 3 1
75 5 1 1
75 10 2 0
75 15 3 0
I'm considering what my next step should be, If I should create a pivot of the data where the app_id would be the row, the role_id would be the columns, and the user_access would be the "data". The "data" would ultimately be rendered as a check box on a website with the appropriate row/column headings.
I'm also considering using a pure ajax/json solution where I will build the json string using pl sql and return the entire string to the client to be processed via jquery.
I'm concerned with the difficulty of the first option (i'm very new to pl sql, and I'm unsure of how to generate a pivot table to be used in this version of oracle (v 10) ) and I'm concerned with the expense of creating an entire json string that will contain so much data.
Any suggestions would be greatly appreciated.
EDIT
I've achieved the pivot table that I desired via the following sql:
SELECT
B.application_nm,
A.user_id,
MAX(DECODE(b.role_name, 'role 1', A.USER_ACCESS, NULL)) "role 1",
MAX(DECODE(b.role_name, 'role 2', A.USER_ACCESS, NULL)) "role 2",
MAX(DECODE(b.role_name, 'role 3', A.USER_ACCESS, NULL)) "role 3",
MAX(DECODE(b.role_name, 'role 4', A.USER_ACCESS, NULL)) "role 4",
MAX(DECODE(b.role_name, 'role 5', A.USER_ACCESS, NULL)) "role 5",
MAX(DECODE(b.role_name, 'role 6', A.USER_ACCESS, NULL)) "role 6"
FROM
vw_user_app_access A LEFT JOIN vw_tbl_app B ON A.app_id = B.app_id
LEFT JOIN vw_tbl_roles C ON A.role_id = C.role_id
GROUP BY B.application_name, A.user_id
ORDER BY A.user_id DESC
Only problem is when in the future we have to add 'role 7'. I have to then go back into this query and add the line MAX(DECODE(b.role_name, 'role 7', A.USER_ACCESS, NULL)) "role 7"
Thinking ahead, this may be an inconvenience, but considering APEX's framework, I would have to go into the report any way to update the number of columns manually i believe.
I'm thinking this may be the "best" solution for now, unless anyone has any other suggestions...
It is possible for an Apex report region based on a dynamic SQL query to return a different number of columns as the query changes. I have set up a simple demo on apex.oracle.com. Type a new column name into the Columns tabular form and press "Add Row", and the Matrix report is re-drawn with an extra column of that name.
You have to:
Base the report on a function that returns the SQL to be run as a string
Select the region attribute "Use Generic Column Names (parse query at runtime only)"
Set the report Headings Type to PL/SQL and then use a function to dynamically return the required column headings as a colon-separated list. Note that this can be different from the column name, although my example uses the same text for both.
If my example isn't clear enough I'll add more info later - I'm out of time now.

Any Mysql guru who knows how to handle a custom group calculation scenario in 1 query?

I hope any sense can be made from my explanation. I was able to create the query, however my query only works for Items related to Containers, AND only if no more than one Items are related. I really hope anybody can be of any assistance!
Consider the following objects:
Container
Person
Item
I have one table where instances of all objects are stored. The table uses a self-referencing parent-child construction so it is db-technically possible to put a Container 'inside' a Person (just mentioning, this is not happening).
Object_Instances
objectid
parentid
typeid
typespecification (same as containerid, personid or itemid => one of three is filled)
containerid
personid
itemid
I have two tables which can be used to link persons/items to containers:
Container_Person
containerid
personid
amount
required (boolean)
Container_Item
containerid
itemid
amount
required (boolean)
(there are also a person/*item* table)
Now for an instance of a container I would like to calculate a number between 0 and 1 which is based on the related Container_Person and Container_Item specification in the following way:
if NO Container_Person/Container_Item are related to the Container => result = 1
if there are related records they should be taken into account in the following manner:
if the Container DOES NOT contain (has a child record of) ALL of the related persons/items which are required => result 0
otherwise:
result = average based on:
(# child records vs amount in Container_xxx relation)
if there are more than 1 person or item related to the container then the 'weight' for the (#records vs amount) value should be the ratio between the related Container_xxx.amount values for that Container.
Here is my current 'solution':
This query only works for one related item to a container. It doesn't take persons into account in any way... If more than one item are related to the container then the query returns multiple records.
So my actual question is: How can I group/sum(calculate to 0 - 1 decimal) the results of the following query based on the _Person / _Item related amount/required specification?
SELECT
Container.name,
Item.name,
(ifnull(Sum(Object_Instance.amount),0) / Container_Item.amount) as value
FROM
Container
Inner Join Object_Instances as Containers
ON Containers.typeid = 'container'
AND Container.containerid = Containers.typespecification
Left Outer Join Container_Item ON Container_Item.containerid = Container.containerid
Left Outer Join Item ON Item.itemid = Container_Item.itemid
Left Outer Join Object_Instance as ContainerItems
ON Item.itemid = ContainerItems.typespecification
AND ContainerItems.typeid = 'item'
AND ContainerItems.parentid = Containers.objectid
WHERE Containers.objectid = 1
GROUP BY
Container.name,
Container_Item.amount,
Item.name,
Container.containerid
When doing complex joins and grouping I will often have to resort to this type of query:
Create grouped (or unique) list
In a new query take the grouped list and then join in a ungrouped list that provides additional details that are needed.