Concat results from one column - java

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;

Related

java.lang.illegalargumentexception no query defined for that name [...]

I have a native query in plsql like this;
create or replace package body DBPK_Monitoring is
PROCEDURE monitoring_Search(cur OUT SYS_REFCURSOR,) is
query VARCHAR(30000);
whereClause VARCHAR(10000);
BEGIN
whereClause := whereClause || ' and ( cnt.contract_status!=7)';
query := ' select itemTitle as "itemTitle", numberOfRow as "numberOfRow" ,
orderNumber as "orderNumber",createDate as "createDate",
priorityNumber as "priorityNumber"
from buy_buy_order bbo
inner join buy_buy_order_item bbi
on bbi.buy_order_id = bbo.id
left outer join core_User_Role shoUserRole
on shoUserRole.id = bbi.buy_Expert_Id
' || whereClause || ' order by ' || orderBy ||
') e WHERE e.rowNO> ' || lower_Bound || ' and e.rowNO<=' ||
upper_Bound;
OPEN cur FOR query
end monitoring_Search;
end DBPK_Monitoring;
I use of this query in repository with hql like this :
Session session = getSession();
Query query = session.getNamedQuery("monitoring_Search").setResultTransformer(Transformers.aliasToBean(MonitoringDto.class));
int firstResultIndex = searchOption.getPageNumber() * searchOption.getPageSize();
query.setInteger("lower_Bound", firstResultIndex);
query.setParameter("upper_Bound", firstResultIndex + searchOption.getPageSize());
query.setString("orderBy", searchOption.getOrder());
query.setParameter("buyOrderNumber", buyOrderNumber);
List<MonitoringDto> list = query.list();
int count = (list.size() > 0L) ? list.get(0).getNumberOfRow() : 0;
return new QueryResult<MonitoringDto>(searchOption.getPageNumber(), count, searchOption.getPageSize(), list);
When I run program, I get this error:
java.lang.illegalargumentexception no query defined for that name
[monitoring_Search]
How can I fix this?
you have to define monitoring_search as a Hibernate named query , you can see the detail about this in this link : https://www.baeldung.com/hibernate-named-query
have a nice day and kiss people around you ;)

Best way for text extraction (classification) over a SQL query in java

I have several SQL queries like this (about 10.000):
SELECT (COLUMN BODY)
FROM (TABLES BODY)
WHERE...
The where part is optional.
I need to extract the "COLUMN BODY" AND "TABLES BODY" from the query, but those are dynamic (I have found SQL functions and subqueries a lot)
Think as getting an vector with the divided query or something like that:
String result = [SELECT, "COLUMN BODY", FROM, "TABLES BODY", WHERE, ... ]
The purpose, I'm working in an "SQL translator" and I need extract those parts from that dynamic queries. I have tried string splitting and other but the result is so frustrating, so I'm looking for an alternative to achieve that. I'm working on a java project.
What is the best way to get that?
Edit
Those are examples of the queries:
SELECT COMPANIA, ANO, TIPO_COBRO, CODIGO, DESCRIPCION FROM SF_DESCRIPCIONES_ESTAND
SELECT AUT_FAMILIARES.COMPANIA, AUT_FAMILIARES.DCTO_EMPLEADO, AUT_FAMILIARES.SUCURSAL_EMPLEADO, AUT_FAMILIARES.IDENTIFICACION, AUT_FAMILIARES.SUCURSAL, AUT_FAMILIARES.CONSECUTIVO, AUT_FAMILIARES.DCTO_IDENTIDAD, AUT_FAMILIARES.PARENTESCO, AUT_FAMILIARES.NOMBRE, AUT_FAMILIARES.FECHANCTO, AUT_FAMILIARES.SEXO, AUT_FAMILIARES.OBSERVACIONES, AUT_FAMILIARES.POLIZA, AUT_FAMILIARES.SALUD, AUT_FAMILIARES.PORCENTAJE, AUT_FAMILIARES.OCUPACION, AUT_FAMILIARES.TELEFONO, AUT_FAMILIARES.POS, AUT_FAMILIARES.AUXILIO_EDUCATIVO, AUT_FAMILIARES.APELLIDO1, AUT_FAMILIARES.APELLIDO2, AUT_FAMILIARES.DIRECCION, AUT_FAMILIARES.ESTADO_ACTUAL, AUT_FAMILIARES.DCTO_IDENTIDAD_A, AUT_FAMILIARES.PARENTESCO_A, AUT_FAMILIARES.NOMBRE_A, AUT_FAMILIARES.SEXO_A, AUT_FAMILIARES.OBSERVACIONES_A, AUT_FAMILIARES.POLIZA_A, AUT_FAMILIARES.SALUD_A, AUT_FAMILIARES.PORCENTAJE_A, AUT_FAMILIARES.OCUPACION_A, AUT_FAMILIARES.TELEFONO_A, AUT_FAMILIARES.POS_A, AUT_FAMILIARES.AUXILIO_EDUCATIVO_A, AUT_FAMILIARES.APELLIDO1_A, AUT_FAMILIARES.APELLIDO2_A, AUT_FAMILIARES.DIRECCION_A, AUT_FAMILIARES.ESTADO_ACTUAL_A, AUT_FAMILIARES.ESTADO, AUT_FAMILIARES.DESTINATARIO, AUT_FAMILIARES.SUCURSAL_DESTINATARIO, AUT_FAMILIARES.TIPO_SOLICITUD, AUT_FAMILIARES.FECHA_APROBACION, AUT_FAMILIARES.ENVIADO, AUT_FAMILIARES.ACTUALIZADO, AUT_FAMILIARES.RUTA, AUT_FAMILIARES.CREATED_BY, AUT_FAMILIARES.DATE_CREATED, AUT_FAMILIARES.MODIFIED_BY, AUT_FAMILIARES.DATE_MODIFIED, AUT_FAMILIARES.N_IDENTIFICACION, AUT_FAMILIARES.EDAD, AUT_FAMILIARES.EDAD_A FROM AUT_FAMILIARES
SELECT DISTINCT CARGOS.ID_DE_CARGO, CARGOS.NOMBRE_DEL_CARGO FROM EV_EVALUADOR_EVALUADO EVAL INNER JOIN CARGOS ON EVAL.COMPANIA = CARGOS.COMPANIA AND EVAL.CARGO_EVALUADO = CARGOS.ID_DE_CARGO WHERE EVAL.COMPANIA = :COMPANIA AND EVAL.CLASE_EVALUACION = :CLASEEVALUACION AND CARGOS.ID_DE_CARGO >= :CODIGO ORDER BY CARGOS.ID_DE_CARGO
SELECT ROWNUM CODIGO, DECODE (ROWNUM, 1,'Activo',2,'Pensionado',3,'Retirado',4,'Suspensión Preventiva',5,'Activarlo para Ajustes Liquidación',6,'Comisión',7,'Encargos')NOMBRE FROM DUAL CONNECT BY ROWNUM < 8
SELECT * FROM ( SELECT A.*, ROWNUM RNUM FROM(SELECT * FROM (SELECT INVENTARIO.CODIGOELEMENTO, INVENTARIO.NOMBRELARGO FROM INVENTARIO WHERE INVENTARIO.COMPANIA = :COMPANIA AND INVENTARIO.TIPO NOT IN ('C') ORDER BY INVENTARIO.COMPANIA, INVENTARIO.CODIGOELEMENTO) WHERE (CASE WHEN CODIGOELEMENTO IS NULL THEN ' ' ELSE UPPER(CODIGOELEMENTO) END) LIKE UPPER(:CODIGOELEMENTO || '%') AND (CASE WHEN NOMBRELARGO IS NULL THEN ' ' ELSE UPPER(NOMBRELARGO) END) LIKE UPPER( '%' || :NOMBRELARGO || '%') ) A WHERE ROWNUM <= (:PAGINICIO + :PAGTAMANIO)) WHERE RNUM > :PAGINICIO

Alternative for COALESCE when all its parameters is null

I am developing a web application (java-maven project) and there is a problem with the query I use. The UI of my web app has 2 search fields: PTT and ID.
The user needs to fill at least one of the fields to make a search. So both fields are nullable but not at the same time.
Before, I had only one field: PTR and it was showing a result array of size 52. (also getting the same number if
I execute select * from users where ptr='smthing' ). After that I added ID field and updated my query as below:
I execute this query in my webservice:
String query= "SELECT t.ptr, t.id ";
query+= "FROM users t ";
query+= "WHERE t.ptr = COALESCE(?, t.ptr) AND " ;
query+= "t.id = COALESCE(?, t.id) ";
and set the fields with the help of Prepared Statement.
Now if the ptr field is filled, but id field is left blank (this can be null or empty string) on the UI and user makes a search, result array size becomes 30. I compared with database
and it does not fetch the rows where ID is null. So coalesce is not what I need when both of its parameters (?, t.ptr) is null.
How can I fix this problem, any suggestions?
I think the logic you want is:
WHERE (t.ptr = ? OR ? IS NULL) AND
(t.id = ? OR ? IS NULL)
I would recommend using named parameters, so you don't have to pass them in twice.
Check this statement:
String query= "SELECT t.ptr, t.id ";
query+= "FROM users t ";
query+= "WHERE (t.ptr = ? OR 1 = ?)"
query+= " AND " ;
query+= "(t.id = ? OR 1 = ?)";
You see that for each of t.id and t.ptr there is a counterpart parameter. In total there will be 4 parameters.
You say that at least 1 of t.id or t.ptr has a valid value, so there are 2 cases:
[1] t.id and t.ptr both have valid values.
For both the counterpart parameters you pass 0 and the query becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = valueid OR 1 = 0)"
In the WHERE part:
t.ptr = valueptr OR 1 = 0 is equivalent to t.ptr = valueptr, and
t.id = valueid OR 1 = 0 is equivalent to t.id = valueid,
and the query finally becomes:
"SELECT t.ptr, t.id FROM users t WHERE t.ptr = valueptr AND t.id = valueid"
[2] from t.id or t.ptr only one has a valid value, let's say this is t.ptr.
For the counterpart of t.ptr you pass 0, for t.id you pass -1 (or any other non existing value) and for the counterpart of t.id you pass 1 and the query becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0) AND (t.id = -1 OR 1 = 1)"
In the WHERE part:
t.ptr = valueptr OR 1 = 0 is equivalent to t.ptr = valueptr, and
t.id = -1 OR 1 = 1 is equivalent to true because 1 = 1 is always true,
and the query finally becomes:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr OR 1 = 0)"
equivalent to:
"SELECT t.ptr, t.id FROM users t WHERE (t.ptr = valueptr)"
(In the case where only t.id has a valid value then you pass an invalid value for t.ptr and 1 for its counterpart and for the counterpart if t.id you pass 0.)
Maybe it seems complicated but it's working and it can be extended for more than 2 columns.
Oracle has build function for this. But it's hard to understand how to use its.
lnnvl(a = b) = true if (a != b ) or ( a = null ) or (b = null)
in your case
WHERE lnnvl(t.ptr != ? ) AND lnnvl( t.id != ?)
LNNVL

How to use SQL Case in Group by Clause?

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];

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")

Categories