I cannot find any refrence on joining multiple selects like the query below in active record, anyone know how such is done?
select a1.act, a1.date, a2.clos
from
(
SELECT count( AccountActiveDate ) act, DATE_FORMAT( AccountActiveDate, '%Y-%m' ) date
FROM customert cust
GROUP BY YEAR( AccountActiveDate ) , MONTH( AccountActiveDate )
) a1
join
(
SELECT count( AccountClosedDate ) clos, DATE_FORMAT( AccountClosedDate, '%Y-%m' ) date
FROM customert cust2
GROUP BY YEAR( AccountClosedDate) , MONTH( AccountClosedDate)
) a2
ON a1.date = a2.date
You can put you sql string like this:
$this->db->query('YOUR QUERY HERE')
Example:
$this->db->query('SELECT * FROM tbl_users WHERE age > 18');
Related
I got an confusing result when working with rownum of Oracle10g.
first query
select * from A where name like '%test' order by name asc
==> return 1 record
second query with rownum
select * from (
select * from A where name like '%test'
order by name asc
)
where rownum <= 2
==> return 2 records
If I remove 'order by' then it will return 1 record.
Any one can help me to explain this behavior?
maybe you wanted this functionality:
select * from (
select X.*, rownum r from (
select * from A where name like '%test'
order by name asc
) X
)
where r <= 2
or alternatively
select * from (
select A.*, ROW_NUMBER() OVER (ORDER BY name) r
from A where name like '%test'
)
where r <= 2
I stuck an hours to display the data in weekly result, but I'm always fail to display that. I'm new in pivot.
Please help me.
Thank you!
Sample data need to produce:
Data,03/10/2014,200,150,186,172
Data,03/16/2014,144,115,181,157
Data,03/22/2014,130,198,136,393
Here's the script:
select 'Data,'''
||(
select listagg(SIM_id,''',''') within group (order by 1)
from (
select distinct substr(dst_channel,1,14) as SIM_id
from table1
where dst_channel like 'SIP/item__-%'
)
)
from dual;
select 'Data'
||','||dtime_day
||','||g1_cnt
||','||g2_cnt
||','||g3_cnt
||','||g4_cnt
from (
select 'Data'
,to_char(d.dtime_day,'MM/dd/yyyy') as dtime_day
,substr(c.dst_channel,1,14) as dst_channel
from table2 d
left join table1
on c.call_date = d.dtime_day
where c.dst_channel like 'SIP/item%'
and c.status like 'ANSWERED%'
and d.dtime_day between trunc(sysdate, 'IW')-(12*7) and trunc(sysdate) -1
)
pivot(
count(dst_channel) as cnt
for dst_channel in (
'SIP/item01' as g1,'SIP/item02' as g2,'SIP/item03' as g3,'SIP/item04' as g4
)
)
order by dtime_day
Result of the query above:
Data,03/10/2014,147,103,86,76
Data,03/11/2014,144,115,81,57
Data,03/12/2014,130,98,59,39
I have two queries with a union as follows:
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = 400
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = 400
group by h1.payment_date, h1.customer_no
Now, I want to use this union in another query.
select * from (
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = p.customer_no
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = p.customer_no
group by h1.payment_date, h1.customer_no ) sq,
payments p
where p.customer_no = 400
and sq.customer_no = p.customer_no
when I run this, I get ORA-00904: "P"."CUSTOMER_NO": invalid identifier. I need to join h1.customer_no to outer queries customer_no.
I have seen some queries with rank but I couldn't quite figure it out. How do I join the inner query with the outer query?
thanks in advance.
Does your payments table have a customer_no column? That seems to be what your error is indicating.
As for how to join the subqueries, you might want to look into factored subqueries. You can do:
WITH z AS (
SELECT ...
UNION
SELECT ...
), y AS (
SELECT ...
)
SELECT ...
FROM y
JOIN z ON y.x = z.x
JOIN some_other_table t ON z.a = t.a
I have this 2 query :
Query #1
SELECT A1.clrn_id ,A1.gpgroup ,A1.cl_id
FROM p_dtl A1
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
and A1.clrn_id in (
select clrn_id
from gp_cl_rn run
where run.clrn_id = a1.clrn_id
and run.finalized_ind = :2
)
AND cl_id IN
(
SELECT cl_id
FROM hm_sal
WHERE oprt_id ='004038'
AND runctrl_id = :3
)
Query #2
SELECT B.eid
FROM JBB B
WHERE B.eid IN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = :1
AND estat=:2
)
AND ESTAT = :2
AND acct_type = :3
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
)
How can I change the clrn_id for the 1st query and B.eid for the 2nd query into EXISTS function? And are the bankid, branchid and acct_id also changeable into EXISTS function?
Thanks in advance!
You can change this to a where exists, but you probably want to join instead:
SELECT B.eid
FROM JBB B
JOIN ( SELECT eid, estat, acct_type, acct_id
, max(acct_id) over ( partition by eid ) as max_acct
FROM pbank
) A
ON b.eid = a.eid
JOIN pbranch C
ON a.bankid = c.bankid
AND a.branchid = c.brahchid
WHERE c.sourceid = :1
AND c.estat = :2
AND a.ESTAT = :3
AND a.acct_type = :4
AND a.acct_id = a.max_acct
By using the analytic function max() you remove the need for a sub-select; it's also a lot clearer, I think, to do things in this manner.
And, your newly added query becomes:
SELECT A1.clrn_id, A1.gpgroup, A1.cl_id
FROM p_dtl A1
JOIN gp_cl_rn run
ON A1.clrn_id = run.clrn_id
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
AND run.clrn_id = a1.clrn_id
AND run.finalized_ind = :2
I notice that you're explicitly using the to_date() function, which implies that you're storing a date as a string. This is bad practice and likely to cause you trouble in the longer run... avoid it if at all possible.
max(acct_id) over ( partition by eid )
is an analytic function; this does exactly the same as the aggregate function max(), except instead of requiring a GROUP BY, it returns the same result for every row in the result set.
This particular use returns the maximum acct_id for every eid. There's a whole host of analytic functions, but the best thing to do is to try it for yourself. There are also several examples available online.
Using a JOIN is not necessarily quicker than a where exists, it just depends what you're after. As with everything I would recommend trying both and seeing what suits your particular situation more.
Generally, they have different purposes; where exists is designed to stop "calculating" rows when a single row that fulfils the conditions is found. JOIN, does everything. In your case as you want everything there may be little to chose between them but I would always use JOIN; just ensure that your indexes are correct.
I hope, it will help you:
SELECT B.eid
FROM JBB B
where exists
(
SELECT 1
FROM pbank A
WHERE exists
(
SELECT 1
FROM pbranch PB
WHERE PB.sourceid = :1
AND PB.estat=:2
and PB.bankid = A.bankid
AND PB.branchid = A.branchid
)
AND ESTAT = :2
AND acct_type = :3
AND A.eid = B.eid
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.eid = B.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
SELECT B.eid
FROM JBB B
JOIN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = 'BNIATB'
AND estat='A'
)
AND ESTAT = 'A'
AND acct_type = 'S'
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = 'A'
AND D.acct_type = 'S')
)
) C on B.eid = c.EID
I have identified a way to get fast paged results from the database using CTEs and the Row_Number function, as follows...
DECLARE #PageSize INT = 1
DECLARE #PageNumber INT = 2
DECLARE #Customer TABLE (
ID INT IDENTITY(1, 1),
Name VARCHAR(10),
age INT,
employed BIT)
INSERT INTO #Customer
(name,age,employed)
SELECT 'bob',21,1
UNION ALL
SELECT 'fred',33,1
UNION ALL
SELECT 'joe',29,1
UNION ALL
SELECT 'sam',16,1
UNION ALL
SELECT 'arthur',17,0;
WITH cteCustomers
AS ( SELECT
id,
Row_Number( ) OVER(ORDER BY Age DESC) AS Row
FROM #Customer
WHERE employed = 1
/*Imagine I've joined to loads more tables with a really complex where clause*/
)
SELECT
name,
age,
Total = ( SELECT
Count( id )
FROM cteCustomers )
FROM cteCustomers
INNER JOIN #Customer cust
/*This is where I choose the columns I want to read, it returns really fast!*/
ON cust.id = cteCustomers.id
WHERE row BETWEEN ( #PageSize * #PageNumber - 1 ) AND ( #PageSize * ( #PageNumber ) )
ORDER BY row ASC
Using this technique the returned results is really really fast even on complex joins and filters.
To perform paging I need to know the Total Rows returned by the full CTE. I have "Bodged" this by putting a column that holds it
Total = ( SELECT
Count( id )
FROM cteCustomers )
Is there a better way to return the total in a different result set without bodging it into a column? Because it's a CTE I can't seem to get it into a second result set.
Without using a temp table first, I'd use a CROSS JOIN to reduce the risk of row by row evaluation on the COUNT
To get total row, this needs to happen separately to the WHERE
WITH cteCustomers
AS ( SELECT
id,
Row_Number( ) OVER(ORDER BY Age DESC) AS Row
FROM #Customer
WHERE employed = 1
/*Imagine I've joined to loads more tables with a really complex where clause*/
)
SELECT
name,
age,
Total
FROM cteCustomers
INNER JOIN #Customer cust
/*This is where I choose the columns I want to read, it returns really fast!*/
ON cust.id = cteCustomers.id
CROSS JOIN
(SELECT Count( *) AS Total FROM cteCustomers ) foo
WHERE row BETWEEN ( #PageSize * #PageNumber - 1 ) AND ( #PageSize * ( #PageNumber ) )
ORDER BY row ASC
However, this isn't guaranteed to give accurate results as demonstrated here:
can I get count() and rows from one sql query in sql server?
Edit: after a few comments.
How to avoid a CROSS JOIN
WITH cteCustomers
AS ( SELECT
id,
Row_Number( ) OVER(ORDER BY Age DESC) AS Row,
COUNT(*) OVER () AS Total --the magic for this edit
FROM #Customer
WHERE employed = 1
/*Imagine I've joined to loads more tables with a really complex where clause*/
)
SELECT
name,
age,
Total
FROM cteCustomers
INNER JOIN #Customer cust
/*This is where I choose the columns I want to read, it returns really fast!*/
ON cust.id = cteCustomers.id
WHERE row BETWEEN ( #PageSize * #PageNumber - 1 ) AND ( #PageSize * ( #PageNumber ) )
ORDER BY row ASC
Note: YMMV for performance depending on 2005 or 2008, Service pack etc
Edit 2:
SQL Server Central shows another technique where you have reverse ROW_NUMBER. Looks useful
#Digiguru
OMG, this really is the wholy grail!
WITH cteCustomers
AS ( SELECT id,
Row_Number() OVER(ORDER BY Age DESC) AS Row,
Row_Number() OVER(ORDER BY id ASC)
+ Row_Number() OVER(ORDER BY id DESC) - 1 AS Total /*<- voodoo here*/
FROM #Customer
WHERE employed = 1
/*Imagine I've joined to loads more tables with a really complex where clause*/
)
SELECT name, age, Total
/*This is where I choose the columns I want to read, it returns really fast!*/
FROM cteCustomers
INNER JOIN #Customer cust
ON cust.id = cteCustomers.id
WHERE row BETWEEN ( #PageSize * #PageNumber - 1 ) AND ( #PageSize * ( #PageNumber ) )
ORDER BY row ASC
So obvious now.