Oracle Query with two 'HAVING' conditions - sql

I have a query and i want to have two HAVING conditions
The first condition is where sum is more than 6000 (Which i have
done)
The second condition is where the COUNT(1) CNT is more than 1 (Which
i need help in)
SELECT SYSDATE,
CUSTOMER.CIF_NO,
CUSTOMER.LONG_NAME_ENG,
TRANSTYPE.short_desc_Eng,
LOCATION.LONG_DESC_ENG ,
COUNT(1) CNT,
SUM(TRANS.AMOUNT) SM
FROM TRANS, CUSTOMER, TRANSTYPE, LOCATION
WHERE TRANS.TRS_AC_CIF = CUSTOMER.CIF_NO
AND TRANS.BRANCH_CODE = LOCATION.BRANCH_CODE
AND TRANS.COMP_CODE = LOCATION.COMP_CODE
AND TRANSTYPE.COMP_CODE = TRANS.COMP_CODE
AND TRANSTYPE.TYPE IN ( 'D' , 'T' )
AND TRANSTYPE.CODE = TRANS.TRX_TYPE
AND TRANS.STATUS = 'P'
AND TRANS.TRS_TYPE = 'R'
AND TRANS.CB_IND = 'C'
GROUP BY CUSTOMER.CIF_NO ,CUSTOMER.LONG_NAME_ENG,
TRANSTYPE.short_desc_Eng, LOCATION.LONG_DESC_ENG
HAVING SUM(TRANS.AMOUNT) > 6000
---------------------------
second having here
----------------------------
ORDER BY CUSTOMER.CIF_NO, CUSTOMER.LONG_NAME_ENG, LOCATION.LONG_DESC_ENG

More than one HAVING clause can not be specified within a SELECT statement, e.g. it's a violation. But add your needed condition such as
HAVING SUM(TRANS.AMOUNT) > 6000 AND COUNT(1) > 1
OR
HAVING SUM(TRANS.AMOUNT) > 6000 OR COUNT(1) > 1
as long as
a GROUP BY clause is present with the SQL statement
aggregations take place within the HAVING clause
P.S. Convert your query syntax to the syntax with explicit JOIN clauses among tables rather than old-style comma-seperated JOINs, and use aliases for the table names

Related

Query - display zero where null in one column and select sum of two columns where not null in next column

I need to display a zero where "Silo Wt" is null, and display the sum of the two values in the Total column even if "Silo Wt" is null.. may not require any changes if I can get a zero in the Silo column
SELECT DISTINCT (coffee_type) AS "Coffee_Type",
(SELECT ItemName
FROM [T01_Item_Name_TBL]
WHERE Item = B.Coffee_Type) AS "Description",
(SELECT COUNT(Green_Inventory_ID)
FROM [Green_Inventory] AS A
WHERE A.Coffee_Type = B.Coffee_Type
AND current_Quantity > 0) AS "Current Units",
SUM((Unit_Weight) * (Current_Quantity)) AS "Green Inv Wt",
(SELECT SUM(TGWeight)
FROM [P04_Green_STotal_TBL] AS C
WHERE TGItem = Coffee_type) AS "Silo Wt",
(SUM((Unit_Weight) * (Current_Quantity)) +
(SELECT SUM(TGWeight)
FROM [P04_Green_STotal_TBL] AS C
WHERE TGItem = Coffee_type)) AS Total
FROM
[Green_Inventory] AS B
WHERE
Pallet_Status = 0
GROUP BY
Coffee_Type
SS of query results now
You just need to wrap them in ISNULL.
However, your query could do with some serious cleanup and simplification:
DISTINCT makes no sense as you are grouping by that column anyway.
Two of the subqueries can be combined using OUTER APPLY, although this requires moving the grouped Green_Inventory into a derived table.
Another subquery, the self-join on Green_Inventory, can be transformed into conditional aggregation.
Not sure whether I've got the logic right, as the subquery did not have a filter on Pallet_Status, but it looks like you would also need to move that condition into conditional aggregation for the SUM, and use a HAVING. It depends exactly on your requirements.
Don't use quoted table or column names unless you have to.
Use meaningful table aliases, rather than A B C.
Specify table names when referencing columns, especially when using subqueries, or you might get unintended results.
SELECT
gi.Coffee_Type,
(SELECT ItemName
FROM T01_Item_Name_TBL AS n
WHERE n.Item = gi.coffee_Type
) AS Description,
ISNULL(gst.TGWeight, 0) AS SiloWt,
ISNULL(gi.GreenInvWt, 0) + ISNULL(gst.TGWeight, 0) AS Total
FROM (
SELECT
gi.Coffee_Type,
COUNT(CASE WHEN gi.current_Quantity > 0 THEN 1 END) AS CurrentUnits,
SUM(CASE WHEN gi.Pallet_Status = 0 THEN gi.Unit_Weight * gi.Current_Quantity END) AS GreenInvWt
FROM
Green_Inventory AS gi
GROUP BY
gi.Coffee_Type
HAVING
SUM(CASE WHEN gi.Pallet_Status = 0 THEN gi.Unit_Weight * gi.Current_Quantity END) > 0
) AS gi
OUTER APPLY (
SELECT SUM(gst.TGWeight) AS TGWeight
FROM P04_Green_STotal_TBL AS gst
WHERE gst.TGItem = gi.Coffee_Type
) AS gst;

Filter if values provided otherwise return everything

Say I have a table t with 2 columns:
a int
b int
I can do a query such as:
select b
from t
where b > a
and a in(1,2,3)
order by b
where 1,2,3 is provided from the outside.
Obviously, the query can return no rows. In that case, I'd like to select everything as if the query did not have the and a in(1,2,3) part. That is, I'd like:
if exists (
select b
from t
where b > a
and a in(1,2,3)
)
select b
from t
where b > a
and a in(1,2,3)
order by b
else
select b
from t
where b > a
order by b
Is there a way to do this:
Without running two queries (one for exists, the other one the actual query)
That is less verbose than repeating queries (real queries are quite long, so DRY and all that stuff)
Using NOT EXISTS with a Sub Query to Determine if condition exists
SELECT b
FROM
t
WHERE
b > a
AND (
NOT EXISTS (SELECT 1 FROM #Table WHERE a IN (1,2,3))
OR a IN (1,2,3)
)
ORDER BY
b
The reason this works is because if the condition exists then the OR statement will include the rows and if the condition does not exist then the NOT EXISTS will include ALL rows.
Or With Common Table Expression and window Function with Conditional Aggregation.
WITH cte AS (
SELECT
b
,CASE WHEN a IN (1,2,3) THEN 1 ELSE 0 END as MeetsCondition
,COUNT(CASE WHEN a IN (1,2,3) THEN a END) OVER () as ConditionCount
FROM
t
)
SELECT
b
FROM
cte
WHERE
(ConditionCount > 0 AND MeetsCondition = 1)
OR (ConditionCount = 0)
ORDER BY
b
I find it a bit "ugly". Maybe it would be better to materialize output from your query within a temp table and then based on count from temp table perform first or second query (this limits accessing the original table from 3 times to 2 and you will be able to add some flag for qualifying rows for your condition not to repeat it). Other than that, read below . . .
Though, bear in mind that EXISTS query should execute pretty fast. It stops whether it finds any row that satisfies the condition.
You could achieve this using UNION ALL to combine resultset from constrained query and full query without constraint on a column and then decide what to show depending on output from first query using CASE statement.
How CASE statement works: when any row from constrained part of your query is found, return resultset from constrainted query else return everything omitting the constraint.
If your database supports using CTE use this solution:
with tmp_data as (
select *
from (
select 'constraint' as type, b
from t
where b > a
and a in (1,2,3) -- here goes your constraint
union all
select 'full query' as type, b
from t
where b > a
) foo
)
SELECT b
FROM tmp_data
WHERE
CASE WHEN (select count(*) from tmp_data where type = 'constraint') > 0
THEN type = 'constraint'
ELSE type = 'full query'
END
;

Assign null if subquery retrieves multiple records. How can it be done?

I have the following query. I simplified it for demo purpose. I am using SQL Server - t-sql
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID )
from tblMain tm
if the subquery returns multiple records, I like to assign tm.LocID to null else if there is only 1 record returned then assign it to tm.LocID. I am looking for a simple way to do this. Any help would be appreciated.
One way I can see is to have a CASE statement and check if (Count * > 1 ) then assign null else return the value but that would require a select statement within a select statement.
You have the right idea about using a case expression for count(*), but it will not require another subquery:
SELECT tm.LocID = (SELECT CASE COUNT(*) WHEN 1 THEN MAX(LocID) END
FROM tblLoc tl
WHERE tl.LocID = tm.LodID )
FROM tblMain tm
or just use a HAVING clause, like
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID
group by locID
having count(*) = 1)
)
from tblMain tm
Your query above (and many of the other answers here) is a correlated subquery which will be very slow since it performs a separate aggregation query on each record. This following will address both your problem and potentially perform a bit better since the count happens in a single pass.
SELECT
CASE
WHEN x.locid IS NOT NULL THEN x.locid
ELSE NULL
END
FROM tblMain m
LEFT JOIN (
SELECT
locid
FROM tblLoc
GROUP BY locid
HAVING COUNT(1) = 1
) x
ON x.locid = m.locid
;
The above is in Postgres syntax (what I'm familiar with) so you would have to make it TSQL compatible.

nhibernate complex query of sql with a group by ROLLUP() of permenant table union all derived query

How would you convert the following sql that contains a case count, group by, union all to nhibernate?
This complex sqql with a group by ROLLUP() of permanent table union all derived query columns
select
CASE
WHEN GROUPING([BUSINESS_UNIT]) = 1 THEN 'Total'
ELSE [BUSINESS_UNIT]
END [BUSINESS_UNIT]
, SUM(InjuryIllnessTtlCount) InjuryIllnessTtlCount
from (
select i.INCIDENT_ID
,b.BUSINESS_UNIT
,case
when (i.INJURY_ILLNESS_TYPE_ID=4 ) then 1 --'Injury/Illness (Near Miss with High Severity Potential)'
else 0
end as InjuryIllnessTtlCount
from tblIncident i
join tblBUSINESS_UNIT b on i.BUS_UNIT_ID = b.BUS_UNIT_ID
--where (CONVERT(varchar(10),i.create_dt, 111) between '2015/01/12' and '2015/05/12')
union all
select 0 incident_id
,b.BUSINESS_UNIT
,0 InjuryIllnessTtlCount
from
tblBUSINESS_UNIT b
) abc
group by ROLLUP(abc.BUSINESS_UNIT)
When it comes to this complicated queries, the conversion to NHibernate either not possible or does not worth it. So my two cents is to go with,
var query = <your query>;
var session = sessionFactory.OpenSession();
var result =session.CreateSQLQuery(query)
.List();
Where the Query is directly executed.

SQL Nested Select statements with COUNT()

I'll try to describe as best I can, but it's hard for me to wrap my whole head around this problem let alone describe it....
I am trying to select multiple results in one query to display the current status of a database. I have the first column as one type of record, and the second column as a sub-category of the first column. The subcategory is then linked to more records underneath that, distinguished by status, forming several more columns. I need to display every main-category/subcategory combination, and then the count of how many of each sub-status there are beneath that subcategory in the subsequent columns. I've got it so that I can display the unique combinations, but I'm not sure how to nest the select statements so that I can select the count of a completely different table from the main query. My problem lies in that to display the main category and sub category, I can pull from one table, but I need to count from a different table. Any ideas on the matter would be greatly appreciated
Here's what I have. The count statements would be replaced with the count of each status:
SELECT wave_num "WAVE NUMBER",
int_tasktype "INT / TaskType",
COUNT (1) total,
COUNT (1) "LOCKED/DISABLED",
COUNT (1) released,
COUNT (1) "PARTIALLY ASSEMBLED",
COUNT (1) assembled
FROM (SELECT DISTINCT
(t.invn_need_type || ' / ' || s.code_desc) int_tasktype,
t.task_genrtn_ref_nbr wave_num
FROM sys_code s, task_hdr t
WHERE t.task_genrtn_ref_nbr IN
(SELECT ship_wave_nbr
FROM ship_wave_parm
WHERE TRUNC (create_date_time) LIKE SYSDATE - 7)
AND s.code_type = '590'
AND s.rec_type = 'S'
AND s.code_id = t.task_type),
ship_wave_parm swp
GROUP BY wave_num, int_tasktype
ORDER BY wave_num
Image here: http://i.imgur.com/JX334.png
Guessing a bit,both regarding your problem and Oracle (which I've - unfortunately - never used), hopefully it will give you some ideas. Sorry for completely messing up the way you write SQL, SELECT ... FROM (SELECT ... WHERE ... IN (SELECT ...)) simply confuses me, so I have to restructure:
with tmp(int_tasktype, wave_num) as
(select distinct (t.invn_need_type || ' / ' || s.code_desc), t.task_genrtn_ref_nbr
from sys_code s
join task_hdr t
on s.code_id = t.task_type
where s.code_type = '590'
and s.rec_type = 'S'
and exists(select 1 from ship_wave_parm p
where t.task_genrtn_ref_nbr = p.ship_wave_nbr
and trunc(p.create_date_time) = sysdate - 7))
select t.wave_num "WAVE NUMBER", t.int_tasktype "INT / TaskType",
count(*) TOTAL,
sum(case when sst.sub_status = 'LOCKED' then 1 end) "LOCKED/DISABLED",
sum(case when sst.sub_status = 'RELEASED' then 1 end) RELEASED,
sum(case when sst.sub_status = 'PARTIAL' then 1 end) "PARTIALLY ASSEMBLED",
sum(case when sst.sub_status = 'ASSEMBLED' then 1 end) ASSEMBLED
from tmp t
join sub_status_table sst
on t.wave_num = sst.wave_num
group by t.wave_num, t.int_tasktype
order by t.wave_num
As you notice, I don't know anything about the table with the substatuses.
You can use inner join, grouping and count to get your result:
suppose tables are as follow :
cat (1)--->(n) subcat (1)----->(n) subcat_detail.
so the query would be :
select cat.title cat_title ,subcat.title subcat_title ,count(*) as cnt from
cat inner join sub_cat on cat.id=subcat.cat_id
inner join subcat_detail on subcat.ID=am.subcat_detail_id
group by cat.title,subcat.title
Generally when you need different counts, you need to use the CASE statment.
select count(*) as total
, case when field1 = "test' then 1 else 0 end as testcount
, case when field2 = 'yes' then 1 else 0 endas field2count
FROM table1