How to write the relational algebra of these SQL queries - relational-algebra

select account_no, amount, customer from transactions where branch = 'Pennywell'
select c.customer_name, c.cust_street, c.cust_city, b.branch_name, b.branch_city, a.account_no, a.balance from customer c, transactions t, accounts a, branch b
where t.customer = c.customer_name and a.account_no = t.account_no and b.branch_name = a.branch_name
select customer_name, cust_city from customer where customer_name not in (select customer from transactions)

The first one is just selection on Pennywell followed by projection on account_no, amount, customer:
\pi_{account_no, amount, customer} (\sigma_branch = 'Pennywell'(transactions))
The second one follows the same principle:
List all your tables:
customer, transactions, accounts, branch
Rename each one of the using \rho:
\rho_c(customer), \rho_t(transactions), \rho_a(accounts),
\rho_b(branch)
Calculate the Cartesian product
\rho_c(customer) x \rho_t(transactions) x \rho_a(accounts) x
\rho_b(branch)
Perform the selection ("where") on the result of step 3 replacing and by conjunctions, or by disjunctions and not by negations:
\sigma_{t.customer = c.customer_name /\ a.account_no = t.account_no /\ b.branch_name = a.branch_name}(\rho_c(customer) x \rho_t(transactions) x \rho_a(accounts) x \rho_b(branch))
Finally perform the projection:
\pi_{c.customer_name, c.cust_street, c.cust_city, b.branch_name, b.branch_city, a.account_no, a.balance}(\sigma_{t.customer = c.customer_name /\ a.account_no = t.account_no /\ b.branch_name = a.branch_name}(\rho_c(customer) x \rho_t(transactions) x \rho_a(accounts) x \rho_b(branch)))
The last query is a bit more tricky and it involves a bit more thinking.
\pi_{customer_name}(transactions)
are all the customers we want to ignore and
\pi_{customer_name}(customer)
are all customers. Hence,
\pi_{customer_name}(customer) - \pi_{customer_name}(transactions)
are all those we want to keep. Finally we need to find their cities (for the sake of simplicity I'm using the join operator |x|):
\pi_{customer_name, cust_city}((\pi_{customer_name}(customer) - \pi_{customer_name}(transactions)) |x| customer)

Related

Join if not exists

I encountered following problem:
I have a long query (let's call it query "Z" ) that includes lots of joins and subqueries. It ouputs two columns:
A: item
B: Integer attribute, range guaranteed to be 1-10
I want to join from table X items (column A) that are not present as output of query Z and give them an arbitrary attribute value 10 (column B).
I tried creating subquery with inner subquery uisng not exists but that requires copying my original query inside and takes a lot of time (I didn't even manage to execute it).
Any suggestions? Thanks
It's not entirely clear from your question but I think you mean table X is a superset of the records from query Z. If so, a simple outer join should give you the result you want:
select coalesce(z.a, x.a) as a
, coalesce(z.b, 10) as b
from x
left outer join ( your query ) z
on z.a = x.a
If X is not a superset of Z then you should try a FULL OUTER JOIN instead.
I have assumed that column A works as a UID for the query Z and the table X. If this is not the case you'll need to tweak the above statement, or edit your question to include more details.
According to your comments , one possibility is to first make a union of the results of your "Z" query and then another select with the addition of only selecting the MIN() of your column B.
So it would look something along the lines of :
SELECT A , MIN(B) FROM
(
(QUERY Z) AS Z
union
(SELECT ITEM as A, 10 as B FROM X)
)
GROUP BY A
I did it similarily to what #Ancaron posted.
SELECT A, B FROM Z
UNION ALL
SELECT A, '10' FROM X
WHERE NOT EXISTS
(
select Z.A
from Z
WHERE Z.A=X.A
)

How to count orders with condition A and B in dax

I have a table with order number and product code. One order can have multiple lines. I would like to count the number of orders which have BOTH product code A AND product code B.
My table looks like this:
OrderNumber ProductCode
Order1 A
Order1 B
Order2 B
Order3 A
Order3 B
Order4 C
So for this result set, the answer would be 2, as both Order1 and Order3 contains both A and B.
I would very much like to create this as a measure in dax.
Thank you.
Try this:
SUMX(
CALCULATETABLE(
VALUES(MyTable[OrderNumber]),
MyTable[ProductCode] = "A"
),
IF(CALCULATE(COUNTROWS(MyTable),MyTable[ProductCode] = "B") > 0,1)
)

Join 3 table to find total cost

We need to find out total cost for each project in XYZ company (from the project). Total cost is considered to be sum of (unit price * quantity) from invoice details table.
To find out total cost for each project you need join 3 tables in the query: XYZ_PROJECTS with XYZ_INVOICES (using PROJECT_NUMBER) and XYZ_INVOICES with XYZ_INVOICE_DETAILS (using INVOICE_NUMBER).
Go to SQL WorkshopSQL Commands. Write and execute a “select” query to select project number, project name from XYZ_PROJECTS, sum(c.qty * c.Unit_price) from XYZ_INVOICE_DETAILS. (You need to add “group by project_number, project_name” at the end of the query since SUM aggregate function is used). Run the query. Your screen should like as follows
I used this to join table but I do not know how to join 3 table at the same time.
select *
from XYZ_PROJECTS c
join XYZ_INVOICES do on c.PROJECT_NUMBER = do.PROJECT_NUMBER
select *
from XYZ_INVOICES i
join XYZ_INVOICE_DETAILS do on i.INVOICE_NUMBER = do.INVOICE_NUMBER
Maybe I do it wrong. Please kindly help me.
select c.project_number, c.project_name, sum(do.qty * do.Unit_price)
from XYZ_PROJECTS c
join XYZ_INVOICES i
on c.PROJECT_NUMBER = i.PROJECT_NUMBER
join XYZ_INVOICE_DETAILS do
on i.INVOICE_NUMBER = do.INVOICE_NUMBER
group by c.project_number, c.project_name
If you need to include zero cost projects who do not have any invoices yet, use left outer join to keep all rows from XYZ_PROJECTS:
select c.project_number, c.project_name, sum(do.qty * do.Unit_price)
from XYZ_PROJECTS c
left join XYZ_INVOICES i
on c.PROJECT_NUMBER = i.PROJECT_NUMBER
left join XYZ_INVOICE_DETAILS do
on i.INVOICE_NUMBER = do.INVOICE_NUMBER
group by c.project_number, c.project_name

Multiple Joins LINQ Query performance

I'm new to LINQ and have very little knowledge.
I have the following complex query. it runs 3 or 4 times slower than the stored procedure which i translated to LINQ.
any tips for me to make it run faster?
var result = from a in db.A
join al in db.AL.Where(q => q.CurrentLocation == 1) on a.AID equals al.AID into tmp_al
from al in tmp_al.DefaultIfEmpty()
join l in db.Lon al.LID equals l.LID into tmp_l
from l in tmp_l.DefaultIfEmpty()
join r in db.R on l.RID equals r.RID into tmp_r
from r in tmp_r.DefaultIfEmpty()
join b in db.B on r.BID equals b.BID into tmp_b
from b in tmp_b.DefaultIfEmpty()
join ap in db.AP.Where(q => q.CurrentProtocol == 1) on a.AID equals ap.AID into tmp_ap
from ap in tmp_ap.DefaultIfEmpty()
join p in db.P on ap.PID equals p.PID into tmp_p
from p in tmp_p.DefaultIfEmpty()
join s in db.S on a.SID equals s.SID into tmp_s
from s in tmp_s.DefaultIfEmpty()
join ans in db.AS on a.ASID equals ans.ASID into tmp_ans
from ans in tmp_ans.DefaultIfEmpty()
join pr in db.P on p.PI equals pr.PID into tmp_pr
from pr in tmp_pr.DefaultIfEmpty()
where a.Active == 1
group a by new { a.Active, pr.LN, pr.FN, b.BN, r.RID, r.R1, p.PN, s.S1, ans.AS1 }
into grp
orderby grp.Key.BN, grp.Key.R1, grp.Key.PN, grp.Key.S1, grp.Key.AS1
select new
{
PIName = grp.Key.LN + " " + grp.Key.FN,
BN = grp.Key.BN,
RID = grp.Key.RID,
R = grp.Key.R1,
PN = grp.Key.PN,
S = grp.Key.S1,
AS = grp.Key.AS1,
NumberOA = grp.Count()
};
Thanks for your answers. #Albin Sunnanbo: i dont know how to check the execution plans. my LINQ runs correctly and produces the required output. it is just slow. I would like to speeden it up. #usr: the original sql is as follows:
sorry about the silly table names. the original code is confidential. so i'm not posting the complete table names.
CREATE PROCEDURE [dbo].[report_CBRP] --
AS
SELECT LN + ' ' + FN As PIN, BN, R.RID, R, PN,
S, AS, COUNT(*) As NOA
FROM A
LEFT JOIN AL
ON A.AID = AL.AID
AND AL.CL = 1
LEFT JOIN L
ON AL.LID = L.LID
LEFT JOIN R
ON L.RID = R.RID
LEFT JOIN B
ON R.BID = B.BID
LEFT JOIN AP
ON A.AID = AP.AID
AND AP.CPl = 1
LEFT JOIN P
ON AP.PID = P.PID
LEFT JOIN S
ON A.SID = S.SID
LEFT JOIN AS
ON A.ASID = AS.ASID
LEFT JOIN P
ON P.PI = P.PID
GROUP BY A.A, LN , FN , B.BN, R.RID, R.R, P.PN,
S.S, AS.AS
HAVING A.A = 1
ORDER BY B.BN, R.R, P.PN, S, AS
GO
It seems you're doing SQL hard life here.
In general, try to avoid so many joins, but rather break them into few small queries.
More than that, you're performing a group by which in itself is an expensive operation, let alone with so many columns
I've noticed that you're joining all the columns in each table. Try to select only the relevant columns.
Also noticed that few of the tables aren't used in the group by like al, ap and l. Do you need them at all??
Use AsNoTracking() for readonly data from EF. In that way you speed up things.
Use SQL Views

Performance issue with inline view in Oracle

I have a query that looks like below and the tables A,T,S have around 1 million rows whereas P have more than 100 million rows. I've newly introduced the inline view "temp" into this query and it caused a drastic degradation in performance. The data retrieved for temp is hardly 50 rows and this inline query runs in a snap when executed alone.
The autotrace statistics show a huge increase in the number of "consistent gets" from a 6 digit number before introducing temp to a 9 digit number after adding this!! Also, more than 90% of LAST_CR_BUFFER_GETS are accounted for the "temp" view. If I extract the data from this view into a temporary table and use that table as part of the joins the performance is very good but that solution is not really feasible for me.
I know the question is very generalized but I'm wondering if there is anything trivially wrong in using this inline view.
Doesn't inline views give the same performance like having this data in a temporary table?
Is there any way I can hint Oracle to use this view in a effective manner and thus increasing performance.
select t.id,
a.date
from A a,
T t,
P p,
S s,
(select id
from S,
R
where s.id = r.id
and r.code = 10
r.code1 = 20
r.name = 'string1' ) temp
where ...cond1
...cond2
...cond2
s.id = temp.id
Best guess, based on my tuning experience is it's probably evaluating the inline view "temp" once per records matched from the result-set obtained by joining A, t, p, s.
The best solution here is to re-write it this way.
Keep in mind that the ORDERED hint assumes that you are providing the tables in the FROM clause in the order in which you want them to join.
I've listed temp and s first, cos that's the only join condition you have listed temp.id = s.id.
Also I'm assuming you have indexes on all the other columns that are part of the join criteria. Let me know if you have any more questions.
select /*+ ordered use_nl(a t p s) */
t.id, a.date
from (
select id
from S,
R
where s.id = r.id and r.code = 10 r.code1 = 20 r.name = 'string1'
) temp,
S s,
A a,
T t,
P p
where ...cond1 ...cond2 ...cond2 and s.id = temp.id
WITH TEMP AS
(select id
from S,
R
where s.id = r.id
and r.code = 10
r.code1 = 20
r.name = 'string1' )
select t.id,
a.date
from A a,
T t,
P p,
S
where ...cond1
...cond2
...cond2
s.id = temp.id;
try to run this query , and please provide the explain plan for this query

Resources