Outer join and self-refer in Oracle - oracle

I have customers with contract at various sites which must be charged.
There are two types of billing address for the sites: sites charged at the customer's address and sites charged to another address.
The kind of site is handled by the field 'status': if the site is charged at the customer's address, the field is equal to 'C'. If it is charged to a different site's address, it is equal to 'A' and the field 'bill_site_id' is filled with the 'site_id' used for billing. I want to retrieve, in one query, the address where I have to send the bill...
Let's say a customer have two sites (the A refers to the B for billing); the request obviously shows the two sites, but I only want the one used for billing (the B).
How to retrieve this one only?
Here is my query (anonymized, so please be gentle :-) )
SELECT CASE wp.status
WHEN 'A'
THEN wp2.name
ELSE c.NAME
END AS NAME,
CASE wp.status
WHEN 'A'
THEN wp2.adress
ELSE c.street
END AS street,
CASE wp.status
WHEN 'A'
THEN wp2.city
ELSE c.city
END AS city,
CASE wp.status
WHEN 'A'
THEN wp2.postcode
ELSE c.postcode
END AS postcode
FROM customer c, site wp, site wp2, customer_site cwp
WHERE c.idcompany = cwp.idcompany
AND cwp.site_id = wp.site_id
AND wp2.site_id(+) = wp.bill_site_id
AND c.idcompany = :someId
GROUP BY wp.status,
wp2.name,
wp2.adress,
wp2.city,
wp2.postcode

I am pretty sure I know what you want but am not 100% sure what 'ch.status' refers to in the query. Also i am not sure that from the information given you can achieve what you want ...
Hopefully the data structures are under your control so you can set it up how you want.
If I read your specification correctly then I think you want/need only 1 instance of the site table in the query, but it is then not clear how you identify the customer's address.
One way round this is for the site table to have an main_address flag. (I think this is the confusion around ch.status)
If there is a flag on the site table then ...
WHERE c.idcompany = cwp.idcompany
AND cwp.site_id = wp.site_id
AND (
(C.STATUS = 'C' AND WP.MAIN_ADDRESS = 1) OR
(C.STATUS = 'A' AND WP.SITE_ID = C.BILL_SITE_ID)
)
Another way would be to have the Main Adress and Billing addresses as foreign keys on the customer table, and to forget about the status flag so :
WHERE WP.SITE_ID = DECODE(C.BILLING_ADDRESS, NULL, C.MAIN_ADDRESS, C.BILLING_ADDRESS)
If this makes no sense then perhaps you can post a DESCRIBE of the tables involved.

Technically a Union is two queries, but you can run it in a single command and it should do what you want so I'm throwing it out as an option. :)
SELECT c.Name AS NAME, c.street AS STREET, c.city AS CITY, c.postcode AS postcode
FROM customer c
INNER JOIN customer_site cwp ON c.idcompany = cwp.idcompany
INNER JOIN site wp ON cwp.site_id = wp.site_id
WHERE c.idcompany = :someid AND wp.status = 'C'
UNION
SELECT wp2.name AS NAME, wp2.adress AS STREET, wp2.city AS CITY, wp2.postcode AS postcode
FROM customer c
INNER JOIN customer_site cwp ON c.idcompany = cwp.idcompany
INNER JOIN site wp ON cwp.site_id = wp.site_id
INNER JOIN site wp2 ON wp.bill_site_id = wp2.site_id
WHERE c.idcompany = :someid AND wp.status = 'A'
I can't see your table structure so it's probably possible to optimize more, but I think that'll help point you in a working direction. This may very well not be any faster then your existing query, but it's a fair bit easier to understand.

Related

Oracle Query don't see what's wrong

I am trying to run this Query but somehow the bottom part Label B doesn't work.
I am new to oracle and I just don't see what's wrong. Can anyone Please Help me? It would be much appreciated.
Its not returning any data when a salesperson is not tied to it. This should still return the information about the base customer regardless.
SELECT DISTINCT X.ship_sales_representative_id,
X.ship_sales_representative_name,
X.ship_sales_regional_name,
X.ship_sales_regional_head,
B.bl_customer_representative_id,
X.sp_customer_representative_id,
B.bill_customer_id,
X.ship_customer_id,
B.bill_customer_address_suffix,
X.ship_customer_address_suffix,
B.bill_customer_name,
X.ship_customer_name,
B.bill_customer_address,
X.ship_customer_address,
B.bill_customer_city,
X.ship_customer_city,
B.bill_customer_statecode,
X.ship_customer_statecode,
B.bill_customer_zipcode,
X.ship_customer_zipcode,
B.bill_customer_phonenumber,
X.ship_customer_phonenumber,
B.bill_customer_faxnumber,
X.ship_customer_faxnumber,
B.bill_customer_email,
X.ship_customer_email,
B.bill_customer_contact,
X.ship_customer_contact
FROM (SELECT DISTINCT S.rep_id Ship_Sales_Representative_ID,
S.rep_name Ship_Sales_Representative_Name,
S.reg_name Ship_Sales_Regional_Name,
S.reg_head Ship_Sales_Regional_Head,
C.rep_id Sp_Customer_Representative_ID,
C.cust_id Ship_Customer_ID,
C.addr_suffix Ship_Customer_Address_Suffix,
C.name Ship_Customer_Name,
C.addr_ln_1 Ship_Customer_Address,
C.city Ship_Customer_City,
C.state_cd Ship_Customer_StateCode,
C.zip_cd Ship_Customer_Zipcode,
C.phone_nbr Ship_Customer_PhoneNumber,
C.fax_nbr Ship_Customer_FaxNumber,
C.email Ship_Customer_Email,
C.contact Ship_Customer_Contact
FROM mdw.customer C,
mdw.sales_org S
WHERE C.rep_id = To_char(S.rep_id, 'FM000000')
AND C.cust_id = v_cust_id
AND C.addr_suffix = v_addr_suffix) X,
(SELECT DISTINCT C.rep_id Bl_Customer_Representative_ID,
C.cust_id Bill_Customer_ID,
C.addr_suffix Bill_Customer_Address_Suffix,
C.name Bill_Customer_Name,
C.addr_ln_1 Bill_Customer_Address,
C.city Bill_Customer_City,
C.state_cd Bill_Customer_StateCode,
C.zip_cd Bill_Customer_Zipcode,
C.phone_nbr Bill_Customer_PhoneNumber,
C.fax_nbr Bill_Customer_FaxNumber,
C.email Bill_Customer_Email,
C.contact Bill_Customer_Contact
FROM mdw.customer C
WHERE C.cust_id = v_cust_id
AND C.addr_suffix = '0001') B;
You probably want to add at the end of the query:
WHERE X.REP_ID = B.REP_ID
(and remove the first DISTINCT) or another condition for the JOIN otherwise this query is going to return all the combinations of records in X with records in B
Since you're looking for
AND C.CUST_ID =v_Cust_ID
you should use it in the join!
Since you're not sure that the information exists in X you should use a LEFT JOIN on X which you can do in Oracle by:
WHERE B.CUST_ID = X.CUST_ID(+)

Too many queries for each user to assets table in joomla

My site generate a lot of queries to database, for each user generates 6 queries. I tried to fine the source of that but my knowlegde was not enough to find. If anyone could help me how to fine the source of that queries?
I used:
Joomla 2.5.8
Main Components: CB, Kunena, SH404SEF, K2, Komento, UddeIM PMS
Main Modules: Gavick News PRO4
Block spam IP
Block bots
The queries which are generate for each user:
SELECT *
FROM `_users`
WHERE `id` = 15
SELECT `g`.`id`,`g`.`title`
FROM `_usergroups` AS g
INNER JOIN `_user_usergroup_map` AS m ON m.group_id = g.id
WHERE `m`.`user_id` = 15
SELECT b.id
FROM _user_usergroup_map AS map
LEFT JOIN _usergroups AS a ON a.id = map.group_id
LEFT JOIN _usergroups AS b ON b.lft <= a.lft
AND b.rgt >= a.rgt
WHERE map.user_id = 15
SELECT a.rules
FROM _assets AS a
WHERE (a.id = 1)
GROUP BY a.id, a.rules, a.lft
SELECT id
FROM _assets
WHERE parent_id = 0
SELECT b.rules
FROM _assets AS a
LEFT JOIN _assets AS b ON b.lft <= a.lft
AND b.rgt >= a.rgt
WHERE (a.id = 1 OR a.parent_id = 0)
GROUP BY b.id, b.rules, b.lft
ORDER BY b.lft
well of course there are going to be a fair amount of queries per use, as you are using extensions such as CB and Kunena, that include queries for each user. Unless you get a message from your host saying too much memory is being used or there is too much traffic, you should be fine.
Joomla is a CMS and therefore these sort of things need to be expected when there are a fair amount of users.
Actually we just fixed a bug in the rules field that was generating an excessive number of queries. It will be fixed in 3.0.4 which is due out next week and whenever another 2.5 release comes out. In the meantime you can fix it yourself.
https://github.com/joomla/joomla-platform/pull/1792
But that's not what you are asking about. The number of queries isn't really the issue (it's totally reasonable) the question is how fast are they.

CRM 2011 - N:N (Many-To-Many) Linq Issue

I have two entities who are N:N - related with each other. With an example I'll show you what I mean :
I have a Session (ave_Session) and there we can put "Trainers"
(ave_trainer) on each Session
I'm tryting to get a list of al the
"Trainers" for a particular Session
They are related to each other in
N:N (relationship name : ave_ave_session_ave_trainer)
I work in VS2010 and with C# => I'm trying to get the data through LINQ
I recently just started with LINQ, so maybe you guys can help me out on this one. The following I've tried and i gave me an "AttributeFrom and AttributeTo must be either both specified or both ommited. You can not pass only one or the other. AttributeFrom: , AttributeTo: ave_trainerid"-error :
var formatteurs = (from f in ORGContext.CreateQuery<ave_trainer>()
join s in ORGContext.CreateQuery<ave_ave_session_ave_trainer>() on f.Id equals s.ave_trainerid.Value
join c in ORGContext.CreateQuery<ave_session>() on s.ave_sessionid.Value equals c.Id
where c.Id == item.Id
select f).ToList();
The item.id is the Id of the session. Thx in advance if you can help me out!
From the MSDN page:
// List the contacts in the Softball team marketing list.
System.Console.WriteLine("List all contacts in Softball Team:");
var members = from c in crm.contacts
join mlm in crm.listmembers on c.contactid equals mlm.entityid
join ml in crm.lists on mlm.listid equals ml.listid
where ml.listname == "Softball Team"
select c;
foreach (var c in members)
{
System.Console.WriteLine(c.fullname + " " + c.emailaddress1);
}
It seems a little backwards the way you have it written now (assuming I'm parsing it correctly).
What you'd normally do is put your 'starting thing' first and then go through the mapping to get to the ones you want. I don't have any CRM 2011 experience, so hopefully I didn't mess this up too much. :)
Also, I'm not a fan of single-character names, so I took the liberty of using longer names :)
var formatteurs = (
// first get the session we're interested in
from session in ORGContext.CreateQuery<ave_session>()
where session.Id == item.Id
// now get the mapping rows that are related to it
join mapping in ORGContext.CreateQuery<ave_ave_session_ave_trainer>()
on session.Id equals s.ave_sessionid.Value
// now get from the mapping rows to the actual trainers
join trainer in ORGContext.CreateQuery<ave_trainer>()
on mapping.ave_trainerid.Value equals trainer.Id
select trainer
).ToList();

Linq query error

I am using following Linq query:
from p in People
where p.Name == "George Lucas"
select p.TitlesActedIn
where TitlesActedIn is a list. People and TitlesActedIn are associted
But I am getting error:
InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Data.Services.Client.ResourceExpression'.
Please suggest solution.
A very simple way to do it:
var query = People
.Expand("TitlesActedIn")
.Where(p => p.Name == "George Lucas")
.First()
.TitlesActedIn.Select(t => t.ShortName);
query.Dump();
Its important to note, that this will crash if the name you pass it does not exist. (The First Operator will throw an exception. You would need to either guarantee that the name exists, or do it in two steps.
If you want to do it in one step it comes down to this:(please note what is coming back)
http://odata.netflix.com/catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn
You need the expand or it will quit evaluating after the .First(), because TitlesActedIn will be empty.
It basically translates to select the Person, include (expand) the TitlesActedIn association, then select the name (client side)
The downside of this is that you are pulling back everything (all fields) from the Titles table. So for every title associated to the Person it is returning (Title, Year, Description, ShortName, etc).
If you did this in two queries you could only pull back "ShortName" from the TitlesActedIn association.
UPDATED: See this question and answer to understand the limitations on Select Many in Data Services + Another solution based on $expand (note this requires the server to support expand)
If this is WCF Data Services and TitlesActedIn is a collection of related movies.
Then you can do this in one query only if Person.Name is the primary key.
To illustrate this:
var titles = from p in people
where p.Name == "George Lucas"
from m in p.TitlesActedIn
select m;
Will do what you want but only if Name is the key of the Person entity, otherwise this is unsupported.
If Name is not the key one way to do this (today) is with two queries, something like this:
var key = (from p in people
where p.Name == "George Lucas"
select new {p.Id}).Single().Id;
var titles = from p in people
where p.Id == key
from m in p.TitlesActedIn
select m;
Another option though would be do an expand:
var george = (from p in people.Expand("TitlesActedIn")
where p.Name == "George Lucas"
select p).Single();
var titles = george.TitlesActedIn;
But that relies on the server supporting $expand - which not all servers do...
Note we are currently working on adding any/all support to OData and WCF Data Services, once that is released you would be able to write:
var titles = from t in titles
where t.Actors.Any(a => a.Name == "George Lucas")
select t;
Hope this helps
Note: in the code that gets the key for George Lucas I create an anonymous type because today WCF Data Services doesn't support materializing primitives directly.
Interestingly, the following works:
from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }
as does this:
(from p in People
where p.Name == "George Lucas"
select new { p.TitlesActedIn }).First().TitlesActedIn
The WCF client automatically adds the expansion call in the URI translation:
http://odata.netflix.com/Catalog/People()?$filter=Name eq 'George Lucas'&$top=1&$expand=TitlesActedIn&$select=TitlesActedIn/*
I get a similar error if I use a group by clause along with the lambda expression to fetch data using WCF Data Service. I got to know that certain operations are not supported by WCF data services. Please make sure you are not using unsupported LINQ operations.
http://msdn.microsoft.com/en-us/library/ee622463.aspx

Need help Understanding Linq group by with joins

Hi I created this Linq query
var k = from account in _session.All<AccountDetail>()
join subscriber in _session.All<Subscriber>() on account.ID equals subscriber.AccID
join subscriberServices in _session.All<SubscriberServce>() on subscriber.ID equals subscriberServices.UserID
join paymentMethod in _session.All<PaymentMethod>() on subscriberServices.PaymentMethod_ID equals paymentMethod.ID
join paymentFrequency in _session.All<PaymentFrequency>() on subscriberServices.PaymentFrequency_ID equals paymentFrequency.ID
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
select new GenerateInvoiceData() { AccID = G.Key.AccID};
I don't understand
group account by new {AccID= account.ID,paymentFrequency= paymentFrequency.Description,paymentMethod= paymentMethod.Description} into G
why do I specify account when I'm not restricted to it in the anonymous type i.e. I can type paymentFrequency.Description.
The group account part is saying what you want the elements in each group to be. The by new { ... } is what you want the key for each group to be. That's not restricted to being part of the information in an element.
As a simplest example, you might have:
from person in people
group person.FirstName by person.LastName
which would give you groups where the key of each group was the last name of all the people represented in the group, and each element of each group would be the first name of someone.
You might want to read two of my Edulinq blog posts:
How query expressions work
The GroupBy method

Resources