PL/SQL-How to implement multiple count statements in a single query when tables and conditions are all different - sql

I'm working on Open Text Content Server Tool that uses PL/SQL Database. What I am trying to do is to fetch count data through 6 different queries all having different conditions and different tables too. I was trying to combine all these 6 count queries but no luck. Below are those 6 queries listed :
Documents Created in A Month:
select count (dataid) from Dtree where
Createdate >= %1 and createdate <= %2 and subtype = 144
Total No of Users:
select count(a.id) from Kuaf a, kuaf b where
a.deleted =0 and a.type =0 and b.id = a.groupid
Unique Users Logged in a Month(Count):
Select count (distinct (performerID))
from dauditnew where auditid=23 and auditdate >= %1 and auditdate <= %2
Users Created in a Month(Count):
Select Count(dataid) FROM DAUDITNEW where AUDITID = 1
AND AUDITSTR LIKE 'Create' and subtype=142 AND
auditdate >= %1 and auditdate <= %2
Users Deleted(Count):
SELECT count(a.userid) from dauditnew a WHERE
a.auditstr = 'Delete' AND
a.AuditDate >= %1 AND
a.AuditDate <= %2 AND
a.UserID in (Select ID from KUAF where Deleted = 1 and Type=0)
Workflows Initiated:
Select count(*) from Wworkaudit WWA where WWA.workaudit_status=1 AND
WWA.workaudit_date >= %1 and WWA.workaudit_date <= %2
Here %1,%2 denote user inputs. Since these 6 queries all have very different conditions, it seems a daunting task for me to combine them. Please help me out.
Thank You.

SELECT (
select count (dataid)
from Dtree
where Createdate BETWEEN :start_date and :end_date
and subtype = 144
) AS Docs_Per_Month,
(
select count(a.id)
from Kuaf a INNER JOIN kuaf b ON (b.id = a.groupid)
where a.deleted = 0
and a.type = 0
) AS Total_No_of_Users,
(
Select count( distinct performerID )
from dauditnew
where auditid = 23
and auditdate BETWEEN :start_date and :end_date
) AS Unique_Users_in_Month,
(
Select Count(dataid)
FROM DAUDITNEW
where AUDITID = 1
AND AUDITSTR = 'Create'
and subtype = 142
AND auditdate BETWEEN :start_date and :end_date
) AS Users_Created_in_Month,
(
SELECT count(a.userid)
from dauditnew a
WHERE a.auditstr = 'Delete'
AND a.auditdate BETWEEN :start_date and :end_date
AND a.UserID in (Select ID from KUAF where Deleted = 1 and Type=0)
) AS Users_Deleted,
(
Select count(*)
from Wworkaudit
where workaudit_status = 1
AND workaudit_date BETWEEN :start_date and :end_date
) AS Workflows_Initiated
FROM DUAL;

Use UNION ALL statement
Ex.
select count (a.x) from a...where...
UNION ALL
select count (b.z) from b...where...
UNION ALL
select count (c.y) from c...where...
etc.
Note: you must use UNION ALL, because if you use regular UNION, duplicate results will not be shown

Related

How can i tune this select statement to prevent it from having select from same table many times?

I need to tune this sql statement provided by developer, how can I speed it up and prevent the HAVING part from select from same users table many time?
SELECT *
FROM (
SELECT t.*, ROWNUM pageination__row__123__
FROM (
SELECT *
FROM (
SELECT SUM(rcm) sum_rcm, SUM(real_amount) sum_ra, MIN(min_share) min_share, MAX(max_share) max_share, SUM(DECODE(rcm_flag, 'Y', 0, rcm)) rcm_n, b.parentid
FROM bet_total b
WHERE draw_date BETWEEN :1 AND :2
GROUP BY parentid
HAVING (
parentid
IN (
SELECT id FROM users u2,
(
SELECT u3.path
FROM users u3
WHERE u3.type = 2 AND u3.lv = 1 AND u3.tesing = 0 AND u3.user_key = :3
) q
WHERE u2.path BETWEEN q.path AND q.path || chr(to_number('FFFFFFFF', 'xxxxxxxx')) AND u2.type = 2
) AND SUM(rcm) > :4
)
) b1, users u5
WHERE (b1.parentid = u5.id AND rcm_n > 0 )
ORDER BY u5.path
) t
) t
WHERE t.pageination__row__123__ <= :5;
SQL Execution Plan
Index of the table Bet_total
Index of table users
You could try using the WITH-Clause.

Distinct keyword not fetching results in Oracle

I have the following query where I unique records for patient_id, meaning patient_id should not be duplicate. Each time I try executing the query, seems like the DB hangs or it takes hours to execute, I'm not sure. I need my records to load quickly. Any quick resolution will be highly appreciated.
SELECT DISTINCT a.patient_id,
a.study_id,
a.procstep_id,
a.formdata_seq,
0,
(SELECT MAX(audit_id)
FROM audit_info
WHERE patient_id =a.patient_id
AND study_id = a.study_id
AND procstep_id = a.procstep_id
AND formdata_seq = a.formdata_seq
) AS data_session_id
FROM frm_rg_ps_rg a,
PATIENT_STUDY_STEP pss
WHERE ((SELECT COUNT(*)
FROM frm_rg_ps_rg b
WHERE a.patient_id = b.patient_id
AND a.formdata_seq = b.formdata_seq
AND a.psdate IS NOT NULL
AND b.psdate IS NOT NULL
AND a.psresult IS NOT NULL
AND b.psresult IS NOT NULL) = 1)
OR NOT EXISTS
(SELECT *
FROM frm_rg_ps_rg c
WHERE a.psdate IS NOT NULL
AND c.psdate IS NOT NULL
AND a.psresult IS NOT NULL
AND c.psresult IS NOT NULL
AND a.patient_id = c.patient_id
AND a.formdata_seq = c.formdata_seq
AND a.elemdata_seq! =c.elemdata_seq
AND a.psresult != c.psresult
AND ((SELECT (a.psdate - c.psdate) FROM dual)>=7
OR (SELECT (a.psdate - c.psdate) FROM dual) <=-7)
)
AND a.psresult IS NOT NULL
AND a.psdate IS NOT NULL;
For start, you have a cartesian product with PATIENT_STUDY_STEP (pss).
It is not connected to anything.
select *
from (select t.*
,count (*) over (partition by patient_id) as cnt
from frm_rg_ps_rg t
) t
where cnt = 1
;

Subquery resultset

I have a query below. Is this the right way to do a subquery?
SELECT App.State_Pstl_Name,
COUNT (DISTINCT App.APLCTN_ID) AS Total_APLCTN
FROM (Select count(distinct b.APLCTN_ID ),
A.Aplctn_Sk,
b.APLCTN_ID,
A.Lctn_Sk,
b.APLCTN_CREATD_DT,
B.Aplctn_Sbmtd_Dt,
c.STATE_PSTL_CD,
c.STATE_PSTL_NAME,
C.Urbn_Rrl_Ind
From MIDAS.Ee_Application_Mmbr_Fact A,
MIDAS.Insrnc_Aplctn_Dmnsn B,
Midas.Lctn_Dmnsn C
Where A.Lctn_Sk In (Select Lctn_Sk
From Midas.Lctn_Dmnsn
Where Flag_Actv_Rec = 'Y' ) And
A.Aplctn_Sk in (select Aplctn_Sk
from MIDAS.Insrnc_Aplctn_Dmnsn
Where Flag_Actv_Rec = 'Y' ) AND
(b.APLCTN_CREATD_DT >= '01-JUL-13' OR
b.APLCTN_CREATD_DT <= '01-JUL-31' )
GROUP BY A.Aplctn_Sk,
b.APLCTN_ID,
a.LCTN_SK,
b.APLCTN_CREATD_DT,
B.Aplctn_Sbmtd_Dt,
c.STATE_PSTL_CD,
c.STATE_PSTL_NAME,
c.URBN_RRL_IND) App
GROUP BY App.STATE_PSTL_NAME
Order By App.State_Pstl_Name

Complex 'order by' or maybe sorting issue

I have a table that looks like this
Group Recipe Priority
0 A 400
0 A 200
0 B 500
0 B 100
1 C 300
1 C 300
1 D 600
Importance is "Group" > "Priority" > "Recipe"
Group 0 has to go first.
Within Group 0, Priority 500 has to go first (since it has higher priority), but for the efficiency, all the recipe has to go first.
After sorting,
it should look like this
Group Recipe Priority
0 B 500
0 B 100
0 A 400
0 A 200
1 D 600
1 C 300
1 C 300
I have tried all different ways to do 'order by' but cannot find a correct way.
thank you for the help
The problem is subtle. You want to order not by priority, but by the maximum priority for a given group/recipe combination. That is, you want to keep all the recipes together based on this max priority.
The following does this:
select t.Group, t.Recipe, t.Priority,
max(priority) over (partition by t.group, t.recipe) as maxpriority
from tablename t
order by t.Group asc, 4 desc, t.Recipe, priority desc
In older versions of Oracle, prior to having analytic functions available, we would have returned the specified result set using a query something like this:
SELECT f.group
, f.recipe
, f.priority
FROM foo f
JOIN ( SELECT g.group
, g.recipe
, MAX(g.priority) AS max_priority
FROM foo g
GROUP BY g.group, g.recipe
) m
ON m.group = f.group AND m.recipe = f.recipe
ORDER BY f.group
, m.max_priority DESC
, f.recipe
, f.priority DESC
This approach works in other databases that don't have analytic functions, such as MySQL.
NOTE: The query above is not NULL-safe, in that the JOIN predicates will eliminate rows that have NULL values for the group or recipe columns. It could be made NULL-safe, but it complicates the SQL a bit.
SELECT f.group
, f.recipe
, f.priority
FROM foo f
JOIN ( SELECT g.group
, g.recipe
, MAX(g.priority) AS max_priority
FROM foo g
GROUP BY g.group, g.recipe
) m
ON (m.group = f.group OR COALESCE(m.group,f.group) IS NULL)
AND (m.recipe = f.recipe OR COALESCE(m.recipe,f.recipe) IS NULL)
ORDER BY f.group
, m.max_priority DESC
, f.recipe
, f.priority DESC
An equivalent result can also be obtained using a correlated subquery in the SELECT list, except that this result set contains an extra "max_priority" column in the result set.
SELECT f.group
, f.recipe
, f.priority
, (SELECT MAX(g.priority)
FROM foo g
WHERE (g.group = f.group OR COALESCE(g.group,f.group) IS NULL)
AND (g.recipe = f.recipe OR COALESCE(g.recipe,f.recipe) IS NULL)
) AS max_priority
FROM foo f
ORDER BY f.group
, 4 DESC
, f.recipe
, f.priority DESC
(I haven't tested whether that correlated subquery could be removed from the SELECT list and entirely moved to the ORDER BY clause. If that worked, we'd eliminate returning the extra column, but that query would look really, really odd.) The other option (to omit that extra column) is to wrap this query (as an inline view) in another query.
SELECT e.group
, e.recipe
, e.priority
FROM (
SELECT f.group
, f.recipe
, f.priority
, (SELECT MAX(g.priority)
FROM foo g
WHERE (g.group = f.group OR COALESCE(g.group,f.group) IS NULL)
AND (g.recipe = f.recipe OR COALESCE(g.recipe,f.recipe) IS NULL)
) AS max_priority
FROM foo f
) e
ORDER BY e.group
, e.max_priority DESC
, e.recipe
, e.priority DESC

T-sql problem with running sum

I am trying to write T-sql script which will find "open" records for one table
Structure of data is following
Id (int PK) Ts (datetime) Art_id (int) Amount (float)
1 '2009-01-01' 1 1
2 '2009-01-05' 1 -1
3 '2009-01-10' 1 1
4 '2009-01-11' 1 -1
5 '2009-01-13' 1 1
6 '2009-01-14' 1 1
7 '2009-01-15' 2 1
8 '2009-01-17' 2 -1
9 '2009-01-18' 2 1
According to my needs I am trying to show only records after last sum for every one articles where 0 sorting by date of last running sum of zero value. So I am trying to abstract (show) records 5 and 6 for Art_id=1 and record 9 for art_id=2. I am using MSSQL2005 and my table has around 30K records with 6000 distinct values of ART_ID.
In this solution I simply want to find all the rows where there isn't a subsequent row for that Art_id where the running sum was 0. I am assuming we can use the ID as a better tiebreaker than TS, since two rows can come in with the same timestamp but they will get sequential identity values.
;WITH base AS
(
SELECT
ID, Art_id, TS, Amount,
RunningSum = Amount + COALESCE
(
(
SELECT SUM(Amount)
FROM dbo.foo
WHERE Art_id = f.Art_id
AND ID < f.ID
)
, 0
)
FROM dbo.[table name] AS f
)
SELECT ID, Art_id, TS, Amount
FROM base AS b1
WHERE NOT EXISTS
(
SELECT 1
FROM base AS b2
WHERE Art_id = b1.Art_id
AND ID >= b1.ID
AND RunningSum = 0
)
ORDER BY ID;
Complete working query:
SELECT
*
FROM TABLE_NAME E
JOIN
(SELECT
C.ART_ID,
MAX(TS) MAX_TS
FROM
(SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A) C
WHERE C.ROW_SUM = 0
GROUP BY C.ART_ID) D
ON
(D.ART_ID = E.ART_ID) AND
(E.TS >= D.MAX_TS)
First we calculate running sums for every row:
SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A
Then we look for last article with 0:
SELECT
C.ART_ID,
MAX(TS) MAX_TS
FROM
(SELECT
ART_ID,
TS,
COALESCE((SELECT SUM(AMOUNT) FROM TABLE_NAME B WHERE (B.Art_id = A.Art_id) AND (B.Ts < A.Ts)),0) ROW_SUM
FROM TABLE_NAME A) C
WHERE C.ROW_SUM = 0
GROUP BY C.ART_ID
You can find all rows where the running sum is zero with:
select cur.id, cur.art_id
from #articles cur
left join #articles prev
on prev.art_id = cur.art_id
and prev.id <= cur.id
group by cur.id, cur.art_id
having sum(prev.amount) = 0
Then you can query all rows that come after the rows with a zero running sum:
select a.*
from #articles a
left join (
select cur.id, cur.art_id, running = sum(prev.amount)
from #articles cur
left join #articles prev
on prev.art_id = cur.art_id
and prev.ts <= cur.ts
group by cur.id, cur.art_id
having sum(prev.amount) = 0
) later_zero_running on
a.art_id = later_zero_running.art_id
and a.id <= later_zero_running.id
where later_zero_running.id is null
The LEFT JOIN in combination with the WHERE says: there can not be a row after this row, where the running sum is zero.