Select multiple tables with same id - oracle11g

I need to select data from four tables based on only one.
In my 'calculated' table, I have all the records I need.
But I need to retrieve some other info for each record, from 'programs', 'term' and 'imported' tables.
'calculated' has ID from 'programs'.
But, to achieve a record from 'imported', I need to join the 'item' table, because 'item' has ID from 'programs' and from 'imported'.
'term' has ID from 'imported'.
So, I tried this:
select c.date,
p.name,
c.name1,
c.name2,
t.date,
i.version,
c.price1,
c.price2,
c.price3
from calculated c, programs p, term t, imported i, item it
where c.programs_id = p.programs_id
and c.programs_id = it.programs_id
and it.imported_id = i.imported_id
and i.term_id = t.term_id;
But when I use count(*) on 'calculated', I get 30k of records, and from my select statement I get more than 130 millions of records.
What am I doing wrong?
What should I do for this to work?

If all duplicates rows are equivalent, u can try smth like this
select c.date,
p.name,
c.name1,
c.name2,
t.date,
i.version,
c.price1,
c.price2,
c.price3
from calculated c, programs p, term t, imported i
where c.programs_id = p.programs_id and
(select imported_id from item it where c.programs_id = it.programs_id and rownum = 1) = i.imported_id
and i.term_id = t.term_id;
where "rownum = 1" is restriction on the selection of one line for oracle.

you forgot to join term table.
Probably you need to add
and t.term_id = i.term_id

Related

Is it possible to compare value to multiple columns in ''In'' clause?

select m.value
from MY_TABLE m
where m.value in (select m2.some_third_value, m2.some_fourth_value
from MY_TABLE_2 m2
where m2.first_val member of v_my_array
or m2.second_val member of v_my_array_2)
Is it possible to write a select similar to this, where m.value is compared to two columns and has to match at least one of those? Something like where m.value in (select m2.first_val, m2.second_val). Or is writing two separate selects unavoidable here?
No. When there are multiple columns in the IN clause, there must be the same number of columns in the WHERE clause. The pairwise query compares each record in the WHERE clause against the records returned by the sub-query. The statement below
SELECT *
FROM table_main m
WHERE ( m.col_1, m.col_2 ) IN (SELECT s.col_a,
s.col_b
FROM table_sub s)
is equivalent to
SELECT *
FROM table_main m
WHERE EXISTS (SELECT 1
FROM table_sub s
WHERE m.col_1 = s.col_a
AND m.col_2 = s.col_b)
The only way to search both columns in one SELECT statement would be to OUTER JOIN the second table to the first table.
SELECT m.*
FROM table_main m
LEFT JOIN table_sub s ON (m.col_1 = s.col_a OR m.col_1 = s.col_b)
WHERE m.col_1 = s.col_a
OR m.col_1 = s.col_b

No more spool space in Teradata while trying Update

I'm trying to update a table with to many rows 388.000.
This is the query:
update DL_RG_ANALYTICS.SH_historico
from
(
SELECT
CAST((MAX_DIA - DIA_PAGO) AS INTEGER) AS DIAS_AL_CIERRE_1
FROM
(SELECT * FROM DL_RG_ANALYTICS.SH_historico A
LEFT JOIN
(SELECT ANO||MES AS ANO_MES, MAX(DIA) AS MAX_DIA FROM DL_RG_ANALYTICS.SH_CALENDARIO
GROUP BY 1) B
ON A.ANOMES = B.ANO_MES
) M) N
SET DIAS_AL_CIERRE = DIAS_AL_CIERRE_1;
Any help is apreciate.
This first thing I'd do is replace the SELECT * with only the columns you need. You can also remove the M derived table to make it easier to read:
UPDATE DL_RG_ANALYTICS.SH_historico
FROM (
SELECT CAST((MAX_DIA - DIA_PAGO) AS INTEGER) AS DIAS_AL_CIERRE_1
FROM DL_RG_ANALYTICS.SH_historico A
LEFT JOIN (
SELECT ANO || MES AS ANO_MES, MAX(DIA) AS MAX_DIA
FROM DL_RG_ANALYTICS.SH_CALENDARIO
GROUP BY 1
) B ON A.ANOMES = B.ANO_MES
) N
SET DIAS_AL_CIERRE = DIAS_AL_CIERRE_1;
What indexes are defined on the SH_CALENDARIO table? If there is a composite index of (ANO, MES) then you should re-write your LEFT JOIN sub-query to GROUP BY these two columns since you concatenate them together anyways. In general, you want to perform joins, GROUP BY and OLAP functions on indexes, so there will be less row re-distribution and they will run more efficiently.
Also, this query is updating all rows in the table with the same value. Is this intended, or do you want to include extra columns in your WHERE clause?

Doctrine DQL - sum of orders by brand and by date in one query

I'm working with Symfony 2.
I need to create a DQL query that would provide me with data to be displayed in the this form:
I need the sum of all orders by brand and by year.
The required tables in the database look like this:
Brand:
VOrder:
So far, I have managed to extract a year, order value and a brand for every orderthe following DQL, but this is nowhere close where I want to be:
$query = $em->createQuery(
"SELECT SUBSTRING(o.date, 1, 4), o.value, b.name
FROM AppBundle:VOrder o
LEFT JOIN AppBundle:Brand b WITH b.id = b
GROUP BY o.date"
);
My question boils down to these:
1. Is it possible to achieve the desired result (see the table above) with only one query?
2. Where do I go from here to get the needed data?
This can be done with a single query, but I think it's best to do this without DQL.
The documentation explains the drawbacks of using DQL for aggregate fields
Have a look at how to run native SQL with doctrine in the docs.
The query itself should do a GROUP BY YEAR(date), and a SUM(value):
SELECT
YEAR(o.date),
SUM(o.value),
b.name
FROM brands b
LEFT JOIN orders o
ON o.brand_id = b.id
GROUP BY YEAR(o.date);
With help from my colleague, I managed to find DQL that does exactly what I was looking for:
$query = $em->createQuery(
"SELECT SUBSTRING(o.date, 1, 4) AS year, SUM(o.value), b.name
FROM AppBundle:Brand b
LEFT JOIN AppBundle:VOrder o WITH o.brand = b.id
GROUP BY year, b.id"
);
There is no YEAR() function on DQL, so the workaround was to use SUBSTRING().
You need next query:
$query = $em->createQuery(
"SELECT YEAR(o.date), sum(o.value), b.name
FROM AppBundle:VOrder o
LEFT JOIN AppBundle:Brand b WITH b.id = o.brand_id
GROUP BY YEAR(o.date), b.name"
);

PL-SQL Lastest record within a group: looking for alternate (PARTITION BY?) approaches

Using PL-SQL, I need to find the record with the lastest INVC_LN_ITEM_STAT_START_DT value within a group of records that share the same value for SHPMNT_LN_ITEM_KEY and RPT_PER_KEY.
How else might this be done? Are there analytical functions for this type of query?
SELECT
m1.*
FROM
HD_INVC_LN_ITEM_STAT m1
LEFT OUTER JOIN HD_INVC_LN_ITEM_STAT m2
ON (
m1.SHPMNT_LN_ITEM_KEY = m2.SHPMNT_LN_ITEM_KEY
AND m1.RPT_PER_KEY = m2.RPT_PER_KEY
AND m1.INVC_LN_ITEM_STAT_START_DT < m2.INVC_LN_ITEM_STAT_START_DT)
WHERE
m2.SHPMNT_LN_ITEM_KEY IS NULL
ORDER BY
m1.SHPMNT_LN_ITEM_KEY
,m1.RPT_PER_KEY
,m1.INVC_LN_ITEM_STAT_CD
,m1.INVC_LN_ITEM_STAT_START_DT
How about this?
SELECT
HD_INVC_LN_ITEM_STAT1.*
FROM
HD_INVC_LN_ITEM_STAT HD_INVC_LN_ITEM_STAT1
INNER JOIN
(
SELECT
HD_INVC_LN_ITEM_STAT2.SHPMNT_LN_ITEM_KEY
,HD_INVC_LN_ITEM_STAT2.RPT_PER_KEY
,MAX(HD_INVC_LN_ITEM_STAT2.INVC_LN_ITEM_STAT_START_DT) AS MAX_INVC_LN_ITEM_STAT_START_DT
FROM
HD_INVC_LN_ITEM_STAT HD_INVC_LN_ITEM_STAT2
GROUP BY
HD_INVC_LN_ITEM_STAT2.SHPMNT_LN_ITEM_KEY
,HD_INVC_LN_ITEM_STAT2.RPT_PER_KEY
) HD_INVC_LN_ITEM_STAT2
ON
HD_INVC_LN_ITEM_STAT1.SHPMNT_LN_ITEM_KEY = HD_INVC_LN_ITEM_STAT2.SHPMNT_LN_ITEM_KEY
AND HD_INVC_LN_ITEM_STAT1.RPT_PER_KEY
= HD_INVC_LN_ITEM_STAT2.RPT_PER_KEY
AND HD_INVC_LN_ITEM_STAT1.INVC_LN_ITEM_STAT_START_DT = HD_INVC_LN_ITEM_STAT2.MAX_INVC_LN_ITEM_STAT_START_DT
ORDER BY
HD_INVC_LN_ITEM_STAT1.SHPMNT_LN_ITEM_KEY
,HD_INVC_LN_ITEM_STAT1.RPT_PER_KEY
,HD_INVC_LN_ITEM_STAT1.INVC_LN_ITEM_STAT_CD
,HD_INVC_LN_ITEM_STAT1.INVC_LN_ITEM_STAT_START_DT;
It's longer but arguably more intuitive. I would like other people's opinions on which is more efficient.

Get count on a joined tables

I have two tables(oracle):
(I have marked the primary keys with a star before the column name)
Table1 Columns are :
*date,
*code,
*symbol,
price,
weight
Table2 columns are :
*descriptionID
code
symbol
date
description
I need to find the below information using query,
For a given code and a symbol on a particular day,is there any description.
for example: code = "AA" and symbol = "TEST" on 2012-4-1 on Table 1 => is there atleast one row like ID=, code ="AA", symbol ="TEST" ,date = 2012-4-1 in table 2
I tried with the below query:
select * from Table1 t1 INNER JOIN
Table2 t2
on t1.code = t2.code and t1.symbol = t2.symbol and
TO_CHAR(t1.date, 'YYYY/MM/DD') = TO_CHAR(t1.date, 'YYYY/MM/DD')
But it doesnt give me output like:
code = AA, symbol = TEST, date 2012-4-1 => descrition count = 10
code = AA, symbol = TEST, date 2012-4-2 => descrition count = 5
code = BB, symbol = HELO, date 2012-4-1 => descrition count = 20
Can some one suggest me a query which can achieve the above output.
I don't see why you need the join:
SELECT count(*)
FROM Table2
WHERE code='AA'
AND symbol = 'TEST'
AND date = to_date('2012-04-01', 'yyyy-mm-dd')
UPDATE: (after reading your comment)
I still don't see why you need the join. Do you need some data from table1 ?
Anyway, if you want the count for all the (code,symbol,date)s then why not group by ?
As for the dates, better use trunc to get rid of the time parts.
So:
SELECT code, symbol, date, count(*)
FROM Table2
GROUP BY code, symbol, date
the Trunc() Method takes a String\Date input and Creates a DATE output that is in this Format: "DD\MM\YYYY".
So Its should do exactly what you want.

Resources