How to use SQL Case in Group by Clause? - java

I'm using SQL Case in my select and in group by clause and I'm working in JAVA. Whenever I execute my java program it says:
Column 'dbo.JOHN_Dashboard.Log_Date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
My Query is:
SELECT EP.Site_Code AS [Site_Code], DB.[Site] AS [Site], DB.[Utility] AS [Utility],
CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0)
WHEN 'Hour' THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
WHEN 'Day' THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
WHEN 'Week' THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
WHEN 'Year' THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)
ELSE DB.[log_date]
END AS [log_date],
SUM(CASE WHEN DB.[value] >= 0 THEN DB.[value] ELSE 0 END) AS [value],
SUM(CASE WHEN DB.[Cost] >=0 THEN DB.[cost] ELSE 0 END) AS [Cost],
SUM(CASE WHEN DB.[CO2] >=0 THEN DB.[CO2] ELSE 0 END) AS [CO],
MT.[Meter_type_name] AS [Meter Type],
MN.[Meter_Name] AS [Meter Name],
U.[Unit_Name] AS [Units],
EP.EnergyPoint_ID AS [Meter_ID],
EP.Parent_ID AS [Parent],
EP.Meter_Description AS [Meter_Description]
FROM [dbo].[JOHN_Dashboard] DB
INNER JOIN [dbo].[EnergyPoints] EP ON DB.[EnergyPoint_ID] = EP.[EnergyPoint_ID]
INNER JOIN [dbo].[Meter_Types] MT ON MT.[Meter_Type_ID] = EP.[Meter_Type_ID]
INNER JOIN [dbo].[Meter_Names] MN ON MN.[Meter_Name_ID] = EP.[Meter_Name_ID]
INNER JOIN [dbo].[Units] U ON U.[Unit_ID] = EP.[Unit_id]
WHERE [log_date] >= ? AND [Log_Date] < DATEADD(DAY, 1, ?)
AND ( ? IS NULL OR EP.Energypoint_ID = ?)
GROUP BY EP.Site_Code, DB.[Site], DB.[Utility], MT.[Meter_type_name],
MN.[Meter_Name], U.[Unit_Name], EP.[EnergyPoint_ID],
EP.[Parent_ID], EP.[Meter_Description],
CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0)
WHEN 'Hour' THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
WHEN 'Day' THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
WHEN 'Week' THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
WHEN 'Year' THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)
ELSE DB.[log_date] END ;
The parameters i'm passing are:
'Week'
'2016-05-16'
'2016-05-22'
6044
6044
'Week'
Note: This query runs without error in SQL Management Studio.

As requested here is a reworked version of your code using a sub-query before grouping. Since I don't have your database I can't guarantee that I have everything exactly right but give this a try.
I recommend always using a sub-query when your group by has complicated logic that will be repeated in the select. Some people would probably drop the second criteria and just say whenever the group by has complicated logic.
SELECT sub.Site_Code, sub.[Site], sub.[Utility], sub.[Meter Type],
sub.[log_date],
SUM(sub.[value]) as [value],
SUM(sub.[Cost]) as [cost],
SUM(sub.[CO]) as [CO],
sub.[Meter Name], sub.[Units], sub.[Meter_ID],
sub.[Parent], sub.[Meter_Description]
FROM (
SELECT EP.Site_Code AS [Site_Code], DB.[Site] AS [Site], DB.[Utility] AS [Utility],
CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0)
WHEN 'Hour' THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
WHEN 'Day' THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
WHEN 'Week' THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
WHEN 'Year' THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)
ELSE DB.[log_date]
END AS [log_date],
CASE WHEN DB.[value] >= 0 THEN DB.[value] ELSE 0 END AS [value],
CASE WHEN DB.[Cost] >=0 THEN DB.[cost] ELSE 0 END AS [Cost],
CASE WHEN DB.[CO2] >=0 THEN DB.[CO2] ELSE 0 END AS [CO],
MT.[Meter_type_name] AS [Meter Type],
MN.[Meter_Name] AS [Meter Name],
U.[Unit_Name] AS [Units],
EP.EnergyPoint_ID AS [Meter_ID],
EP.Parent_ID AS [Parent],
EP.Meter_Description AS [Meter_Description]
FROM [dbo].[JOHN_Dashboard] DB
INNER JOIN [dbo].[EnergyPoints] EP ON DB.[EnergyPoint_ID] = EP.[EnergyPoint_ID]
INNER JOIN [dbo].[Meter_Types] MT ON MT.[Meter_Type_ID] = EP.[Meter_Type_ID]
INNER JOIN [dbo].[Meter_Names] MN ON MN.[Meter_Name_ID] = EP.[Meter_Name_ID]
INNER JOIN [dbo].[Units] U ON U.[Unit_ID] = EP.[Unit_id]
WHERE [log_date] >= ? AND [Log_Date] < DATEADD(DAY, 1, ?)
AND ( ? IS NULL OR EP.Energypoint_ID = ?)
) sub
GROUP BY sub.Site_Code, sub.[Site], sub.[Utility], sub.[Meter Type],
sub.[Meter Name], sub.[Units], sub.[Meter_ID],
sub.[Parent], sub.[Meter_Description], sub.[log_date];

Related

Oracle Stored Procedure Slow Performance

i have a simple stored procedure. i use this to show data from my db. i want to optimize this query because i think this is slow. 31 seconds for 220.000 rows. so this is my query
BEGIN
sql_base :=
'SELECT
p.id
,p.cis
,p.account_no
,p.name
,p.address
,p.village_name
,p.postal_code
,p.subdistrict_name
,p.regency_name
,p.province_name
,p.country_name
,m.group_id
,i.name
,m.id
,m.name
,m.address
,m.village_name
,m.postal_code
,m.subdistrict_name
,m.regency_name
,m.province_name
,m.country_name
,listagg (mMcc.name, '','') within group (order by mMcc.name) merchantMccName
,o.mid
,o.name
,o.mcc_id outletMccId
,REPLACE(REPLACE(o.jenis_outlet,''ecomm'',''e-commerce''),''retail'',''toko'') jenisOutlet
,o.MODIFIEDDATE
,o.CREATEDDATE
,o.CC_testing_ACCOUNTNO outletCcAccountNo
,o.DEBIT_testing_ACCNO outletDebitAccountNo
,MCC.name outletMccName
,o.MCC_CODE outletMccCode
,m.code merchantCode
,p.jenisn abah jenisn abah
,p.segmenn abah segmenn abah
,p.IDENTITY_NO identityNo
,p.IDENTITY_TYPE identityType
,o.status status
,NVL(o.ISOUTLET, 0) isOutlet
,NVL(p.IS_ACCOUNT_testing, 0) isAccounttesting
,p.ACCOUNT_OTHERBANK_NO accountOtherbankNo
,p.ACCOUNT_OTHERBANK_BANKNAME accountOtherbankBankname
,p.ACCOUNT_OTHERBANK_NO pemilikOtherBankAccountNo
,o.ADDRESS1 outletAddress1
,o.ADDRESS2 outletAddress2
,o.VILLAGE_NAME outletVillageName
,o.POSTAL_CODE outletPostalCode
,o.SUBDISTRICT_NAME outletSubdistrictName
,o.REGENCY_NAME outletRegencyName
,o.PROVINCE_NAME outletProvinceName
,C E WHEN NVL(o.IS_CC_TESTING,0)=1 THEN ''TESTING'' ELSE TO_CHAR(o.CC_OTHERBANK_NAME) END outletCcBankName
,C E WHEN NVL(o.IS_DEBIT_TESTING,0)=1 THEN ''TESTING'' ELSE TO_CHAR(o.CC_OTHERBANK_NAME) END outletDebitBankName
,NVL(o.IS_CC_OTHERBANK,0) isCcOtherBank
,NVL(o.IS_CC_TESTING,0) is_cc_testing
,NVL(o.IS_DEBIT_testing,0) is_debit_testing
,o.CC_OTHERBANK_ACCNO ccOtherBankAccNo
,o.QRIS_STATIS_NMID nmid
,o.AGENT_BANK_CODE outletAgentBank
FROM PEMILIK p
LEFT JOIN mytable m ON p.ID = m.PEM_ID
LEFT JOIN mytable2 i ON m.GROUP_ID = i.ID
INNER JOIN mytable3 o ON m.ID = o.MERCH_ID
LEFT JOIN mytable4 mMcc ON m.ID = mMcc.MERCH_ID
LEFT JOIN mytable5 mcc ON MCC.ID = o.MCC_ID
GROUP BY
*SAME LIKE SELECT*;
final_result:='SELECT rec.*, count (*) over ()CountData FROM ('
|| sql_base || ') rec '
||WHERE_Q
||ORDERBY_Q||' '||PAGING_Q ;
OPEN O_RESULT_REC FOR
final_result;
i already tried to change the query but still i think my query still not good. any tips to improve my query? should i change the connection in java? or this is just query problem?

Concat results from one column

How to concat results from column in Oracle SQL. same function as GROUP_CONCAT().
I have data like this
I want to get the result like this.
I already used listagg()
SELECT LISTAGG(S.MEASURE_WEIGHT, '/') WITHIN GROUP (ORDER BY S.Plan_id)
result are:
Without zeroes :(
can someone help me?
It seems like you want conditional aggregation:
select
measure_id,
max(case when plan_id = 1050 then measure_weight else 0 end)
|| '/'
|| max(case when plan_id = 1055 then measure_weight else 0 end) weight
from mytable
group by measure_id
Possibly this query using two subqueries may work:
SELECT
measure_id,
TO_CHAR(NVL((
SELECT weight FROM table t1
WHERE t1.measure_id = t.measure_id AND t1.plan_id = t.min_id AND t.min_id = 1050), 0))
|| '/' ||
TO_CHAR(NVL((
SELECT weight FROM table t2
WHERE t2.measure_id = t.measure_id AND t2.plan_id = t.max_id AND t.max_id = 1055), 0))
FROM (
SELECT measure_id, min(plan_id) min_id, max(plan_id) max_id
FROM table
GROUP BY measure_id
) t;

Case expressions and aliases in jOOQ 3.5.3

I'm having a problem with expressing the following query in jOOQ
SELECT s.season_name, l.league_name,
COUNT(CASE WHEN m.full_time_result = 'H' THEN 'H' END) AS home_wins,
COUNT(CASE WHEN m.full_time_result = 'D' THEN 'D' END) AS draws,
COUNT(CASE WHEN m.full_time_result = 'A' THEN 'A' END) AS away_wins,
COUNT(m.full_time_result) AS all_matches
FROM football_stats.matches AS m
JOIN football_stats.seasons AS s USING (season_id)
JOIN football_stats.leagues AS l USING (league_id) GROUP BY s.season_name, l.league_name
My java code for this is:
final Field<String> homeWins = DSL.decode().when(MATCHES.FULL_TIME_RESULT.eq(HOME_WIN), HOME_WIN).as("home_wins");
final Field<String> draws = DSL.decode().when(MATCHES.FULL_TIME_RESULT.eq(DRAW), DRAW).as("draws");
final Field<String> awayWins = DSL.decode().when(MATCHES.FULL_TIME_RESULT.eq(AWAY_WIN), AWAY_WIN).as("away_wins");
final Field<?>[] fields = {SEASONS.SEASON_NAME, LEAGUES.LEAGUE_NAME, DSL.count(homeWins), DSL.count(draws), DSL.count(awayWins), DSL.count()};
final SelectQuery<Record> query = dslContext.selectQuery();
query.addSelect(fields);
query.addFrom(MATCHES);
query.addJoinOnKey(SEASONS, JoinType.JOIN, Keys.MATCHES__FK_MATCHES_SEASONS);
query.addJoinOnKey(LEAGUES, JoinType.JOIN, Keys.MATCHES__FK_MATCHES_LEAGUES);
query.addGroupBy(SEASONS.SEASON_NAME,LEAGUES.LEAGUE_NAME);
final Record result = query.fetchOne();
And the query generated by jOOQ is:
select
"football_stats"."seasons"."season_name",
"football_stats"."leagues"."league_name",
count("home_wins"),
count("draws"),
count("away_wins"),
count(*)
from "football_stats"."matches"
join "football_stats"."seasons"
on "football_stats"."matches"."season_id" = "football_stats"."seasons"."season_id"
join "football_stats"."leagues"
on "football_stats"."matches"."league_id" = "football_stats"."leagues"."league_id"
group by
"football_stats"."seasons"."season_name",
"football_stats"."leagues"."league_name"
it results in
ERROR: column "home_wins" does not exist
However, when I omit .as("alias_name"), then jOOQ generates
select
"football_stats"."seasons"."season_name",
"football_stats"."leagues"."league_name",
count(case when "football_stats"."matches"."full_time_result" = 'H' then 'H' end),
count(case when "football_stats"."matches"."full_time_result" = 'D' then 'D' end),
count(case when "football_stats"."matches"."full_time_result" = 'A' then 'A' end),
count(*)
from "football_stats"."matches"
join "football_stats"."seasons"
on "football_stats"."matches"."season_id" = "football_stats"."seasons"."season_id"
join "football_stats"."leagues"
on "football_stats"."matches"."league_id" = "football_stats"."leagues"."league_id"
group by
"football_stats"."seasons"."season_name",
"football_stats"."leagues"."league_name"
How can I make jOOQ to generate it like count(case when "football_stats"."matches"."full_time_result" = 'A' then 'A' end) as 'away_wins'?
Also, can I make it generate USING instead of ON (addJoinUsing method also generates ON)?
You aliased the wrong expression
In SQL, you wrote:
COUNT(CASE WHEN m.full_time_result = 'H' THEN 'H' END) AS home_wins
With jOOQ, you wrote:
homeWins = decode().when(MATCHES.FULL_TIME_RESULT.eq(HOME_WIN), HOME_WIN).as("home_wins");
and then:
DSL.count(homeWins);
So, jOOQ generated exactly the SQL you wrote.
You intended, however, to write this:
homeWins = decode().when(MATCHES.FULL_TIME_RESULT.eq(HOME_WIN), HOME_WIN);
and then:
DSL.count(homeWins).as("home_wins");
Side-note:
In the upcoming jOOQ 3.6, you will be able to simplify your COUNT(CASE...) expression by using the SQL standard FILTER clause on aggregate functions:
DSL.count().filterWhere(MATCHES.FULL_TIME_RESULT.eq(HOME_WIN)).as("home_wins")

Row_number() and partition by statement of sql is not working in java class

I have a sql query which is working fine in sql server 2012 but not working in java class .It gives error Incorrect syntax near 'INDUS2_VACUUM'. some error is always shown near rn"+.Whatever changes I do error is shown near rn. Can't we execute such query in java class and obtain the ResultSet?
Sql query in my java class is
WITH cte AS (SELECT b.logtime,b.beam_current,b.beam_energy,"+
"case when a.st2_vs2_bag1_onoff=0 then c.st2_vs2_bag1_rb ELSE 0 END as st2_vs2_bag1_rb,"+
"CASE when a.st2_vs2_bag2_onoff=0 then c.st2_vs2_bag2_rb else '0' END as st2_vs2_bag2_rb,"+
"CASE when a.st2_vs2_bag3_onoff=0 then c.st2_vs2_bag3_rb else '0' END as st2_vs2_bag3_rb,"+
"CASE when a.st2_vs2_bag4_onoff=0 then c.st2_vs2_bag4_rb else '0' END as st2_vs2_bag4_rb,"+
"CASE when a.st2_vs2_bag5_onoff=0 then c.st2_vs2_bag5_rb else '0' END as st2_vs2_bag5_rb,"+
"CASE when a.st2_vs2_bag6_onoff=0 then c.st2_vs2_bag6_rb else '0' END as st2_vs2_bag6_rb,"+
"CASE when a.st2_vs2_bag7_onoff=0 then c.st2_vs2_bag7_rb else '0' END as st2_vs2_bag7_rb,"+
"CASE when a.st2_vs2_bag8_onoff=0 then c.st2_vs2_bag8_rb else '0' END as st2_vs2_bag8_rb,"+
"CASE when a.st2_vs2_bag9_onoff=0 then c.st2_vs2_bag9_rb else '0' END as st2_vs2_bag9_rb ,"+
"Row_number() OVER(partition BY b.beam_current ORDER BY b.logtime) rn"+
"FROM INDUS2_VACUUM.dbo.main_vacuum_analog c INNER JOIN INDUS2_VACUUM.dbo.main_vacuum_status a"+
"ON c.logtime = a.logtime INNER JOIN INDUS2_BDS.dbo.DCCT b ON a.LOGTIME = b.LOGTIME"+
"WHERE b.logtime BETWEEN '2014-08-09 00:00:00' AND '2014-08-09 23:59:59'"+
"AND b.beam_current in('10.01', '20.02', '39.97', '40.04', '50.05', '60.0', '69.96', '79.97', '90.03', '109.96', '119.97', '129.98')AND b.beam_energy BETWEEN '550' AND '551')"+
"Select logtime,beam_current,beam_energy,st2_vs2_bag1_rb,st2_vs2_bag2_rb,st2_vs2_bag3_rb,st2_vs2_bag4_rb,st2_vs2_bag5_rb,st2_vs2_bag6_rb,st2_vs2_bag7_rb,st2_vs2_bag8_rb,st2_vs2_bag9_rb"+
"from cte where rn=1 order by logtime";
I would say it's because you're missing a space before from, and end up with this:
ORDER BY b.logtime) rnFROM INDUS2_VACUUM
Edit: You seem to have a lot of these issues. Maybe you should print out the SQL and check what it actually says.

SQLite - Tricky query for max(column)

I have built a schema with SQL Fiddle:
SQL Fiddle - Schema
We have these columns in the testtable:
id [int] as primary key (not used -> not important)
end [int] - if a new stream is written into the table all but the last time have value '0' and the last one has the value '1'. This is to refer that the input-stream is finished here.
time_abs [int] - an absolute time (e.g. in minute-steps).
r_m [double] - is the mass rate sumed up over the time
T_r [double] - does not matter
type [string] - also does not matter here
x0 [string] - departure (e.g. where does the water come from?)
x1 [string] - destination (e.g. where does the water flow in?)
As you can see in the SQL Fiddle Schema we query every mass at a certain location and at a certain time like this:
SELECT
(SELECT (SELECT total(r_m)
FROM testtable
WHERE time_abs=11 AND end=0 AND x1='vessel2') +
(SELECT total(r_m)
FROM testtable
WHERE end=1 AND time_abs <=11 AND x1='vessel2')
)
-
(SELECT (SELECT total(r_m)
FROM testtable
WHERE time_abs=11 AND end=0 AND x0='vessel2') +
(SELECT total(r_m)
FROM testtable
WHERE end=1 AND time_abs <=11 AND x0='vessel2')
)
Which works well and fast.
But what we now want to query is the maximum of r_m at a certain time range.
E.g. pseudo code:
SELECT max(total(r_m))
WHERE time_abs BETWEEN 1 AND 30 & SELECT time_abs WHERE r_m=max ...
So that the result of this pseudo query is (123, 13-24) (max(total mass), time span where total mass=max) (manually checked at the SQL Fiddle Schema).
Any ideas?
Here's a query that shows the level in vessel 2 between 5 and 26 seconds:
select times.time_abs
, sum(
case when x1 = 'vessel2' and ([end] = 1 or times.time_abs = tt.time_abs)
then r_m else 0 end -
case when x0 = 'vessel2' and ([end] = 1 or times.time_abs = tt.time_abs)
then r_m else 0 end
) as lvl
from (
select distinct time_abs
from testtable
where time_abs between 5 and 26
) times
join testtable tt
on tt.time_abs <= times.time_abs
and 'vessel2' in (tt.x0, tt.x1)
group by
times.time_abs
To just display the maximum, you can:
select max(lvl)
from (
...query from above...
) as SubQueryAlias
Live example at SQL Fiddle.

Categories