ORA-00979: not a GROUP BY expression ORACLE - sql

select to_char(r.rut_cli,'99G999G999')||'-'|| r.dv_cli RUT_CLIENTE ,
to_char(ROUND(r.monto_compras),'$999,999,999,999') AS "MontoComprasRegistrado"
, to_char(ROUND(sum(s.total_sali)),'$999,999,999') AS "MontoComprasCalculado"
, to_char(ROUND(sum(s.total_sali) - r.monto_compras),'$999,999,999,999') AS "Dif.MontoCalculado|Registrado"
from resumen_vta_cliente r join det_despacho d on r.rut_cli=d.rut_cli
join salida s on d.cod_sali=s.cod_sali
join det_salida z on (s.cod_sali=z.cod_sali)
where d.estado_des='E'
and z.cod_prod = (select cod_prod from producto where cod_tipo ='&CODIGO_TIPO')
and s.estado_sali='V'
group by r.rut_cli, r.dv_cli
having r.monto_compras > (select min(total_sali) from salida)
order by r.rut_cli,r.dv_cli;
I don't know why I'm getting this error
ORA-00979: not a GROUP BY expression
Error en la lĂ­nea: 26, columna: 9
Line 26 is having r.monto_compras > (select min(total_sali) from salida)

Let's start from remove r.monto_compras in your sql, this will work.
select to_char(r.rut_cli,'99G999G999')||'-'|| r.dv_cli RUT_CLIENTE ,
-- to_char(ROUND(r.monto_compras),'$999,999,999,999') AS "MontoComprasRegistrado"
, to_char(ROUND(sum(s.total_sali)),'$999,999,999') AS "MontoComprasCalculado"
-- , to_char(ROUND(sum(s.total_sali) - r.monto_compras),'$999,999,999,999') AS "Dif.MontoCalculado|Registrado"
from resumen_vta_cliente r join det_despacho d on r.rut_cli=d.rut_cli
join salida s on d.cod_sali=s.cod_sali
join det_salida z on (s.cod_sali=z.cod_sali)
where d.estado_des='E'
and z.cod_prod = (select cod_prod from producto where cod_tipo ='&CODIGO_TIPO')
and s.estado_sali='V'
group by r.rut_cli, r.dv_cli
-- having r.monto_compras > (select min(total_sali) from salida)
order by r.rut_cli,r.dv_cli;
You may get result from it.
And now, remove comment and then add r.monto_compras to group by clause.
group by r.rut_cli, r.dv_cli, r.monto_compras
having r.monto_compras > (select min(total_sali) from salida)
But I'm not sure work or not, I don't have any script for this.
If you have table script, we need it to solve your problem as soon as possible.
Here is what I've tested.(Note: I tested this on PostgreSQL + Oracle)
create table resumen_vta_cliente(
rut_cli integer,
dv_cli varchar(10),
monto_compras integer
);
create table det_despacho(
rut_cli integer,
cod_sali integer,
estado_des varchar(10)
);
create table salida(
cod_sali integer,
estado_sali varchar(10),
total_sali integer
);
create table det_salida(
cod_sali integer,
estado_sali varchar(10),
cod_prod varchar(10)
);
create table producto(
cod_prod varchar(10),
cod_tipo varchar(10)
);

Related

SQLite: Workaround for SQLite-TRIGGER with WITH

I'm working on a project to monitor downtimes of production lines with an embedded device. I want to automate acknowledging of these downtimes by generic rules the user can configure.
I want to use a TRIGGER but get a syntax error near UPDATE even though the documentation says it should be fine to use the WITH statement.
CREATE TRIGGER autoAcknowledge
AFTER UPDATE OF dtEnd ON ackGroups
FOR EACH ROW
WHEN old.dtEnd IS NULL AND new.dtEnd IS NOT NULL
BEGIN
WITH sub1(id, stationId, groupDur) AS (
SELECT MIN(d.id), d.station,
strftime('%s', ag.dtEnd) - strftime('%s', ag.dtStart)
FROM ackGroups AS ag
LEFT JOIN downtimes AS d on d.acknowledge = ag.id
WHERE ag.id = old.id
GROUP BY ag.id ),
sub2( originId, groupDur, reasonId, above, ruleDur) AS (
SELECT sub1.stationId, sub1.groupDur, aar.reasonId, aar.above, aar.duration
FROM sub1
LEFT JOIN autoAckStations AS aas ON aas.stationId = sub1.stationId
LEFT JOIN autoAckRules AS aar ON aas.autoAckRuleId = aar.id
ORDER BY duration DESC )
UPDATE ackGroups SET (reason, dtAck, origin)=(
SELECT reasonId, datetime('now'), originId
FROM sub2 as s
WHERE ( s.ruleDur < s.groupDur AND above = 1 ) OR (s.ruleDur > s.groupDur AND above = 0)
LIMIT 1
)
WHERE id = old.id;
END
Background: First we have the downtimes table. Each production line consists of multiple parts called stations. Each station can start the line downtime and they can overlap with other stations downtimes.
CREATE TABLE "downtimes" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"station" integer NOT NULL,
"acknowledge" integer,
"dtStart" datetime NOT NULL,
"dtEnd" datetime,
"dtLastModified" datetime)
Overlaping downtimes are grouped to acknowledge groups using TRIGGER AFTER INSERT on downtimes to set acknowledge id right or create a new group.
CREATE TABLE "ackGroups" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"reason" integer,
"dtAck" datetime,
"dtStart" datetime NOT NULL,
"dtEnd" datetime,
"line" integer NOT NULL,
"origin" integer)
The autoAckRules table represents the configuration. The user decides whether the rule should apply to durations higher or lower a certain value and which rasonId should be used to acknowledge.
CREATE TABLE "autoAckRules" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"description" text NOT NULL,
"reasonId" integer NOT NULL,
"above" bool NOT NULL,
"duration" real NOT NULL)
The autoAckStations table is used to manage M:N relationship. Each rule allow multiple stations which started the ackGroup.
CREATE TABLE autoAckStations (
autoAckRuleId INTEGER NOT NULL,
stationId INTEGER NOT NULL,
PRIMARY KEY ( autoAckRuleId, stationId )
)
When the last downtime ends dtEnd of ackGroups is set to datetime('now') and the trigger is fired to check if there is a autoAckRule that fits.
If I substitute the sub selects with a SELECT .. FROM( SELECT .. FROM(SELECT .. FROM ))) cascade
is there a nice way to avoid the need to write and evaluate it twice?
Or am I missing something stupid?
Common table expression are not supported for statements inside of triggers. You need to convert CTE to sub-query such as
CREATE TRIGGER autoAcknowledge
AFTER UPDATE OF dtEnd ON ackGroups
FOR EACH ROW
WHEN old.dtEnd IS NULL AND new.dtEnd IS NOT NULL
BEGIN
UPDATE ackGroups
SET (reason, dtAck, origin)= (
SELECT reasonId, datetime('now'), originId
FROM (SELECT sub1.stationId AS originId,
sub1.groupDur AS groupDur,
aar.reasonId AS reasonId,
aar.above AS above,
aar.duration AS ruleDur
FROM (SELECT MIN(d.id) AS id,
d.station AS stationId,
strftime('%s', ag.dtEnd) - strftime('%s', ag.dtStart) AS groupDur
FROM ackGroups AS ag
LEFT
JOIN downtimes AS d
ON d.acknowledge = ag.id
WHERE ag.id = old.id
GROUP BY ag.id ) AS sub1
LEFT
JOIN autoAckStations AS aas
ON aas.stationId = sub1.stationId
LEFT
JOIN autoAckRules AS aar
ON aas.autoAckRuleId = aar.id
ORDER BY duration DESC) as s
WHERE ( s.ruleDur < s.groupDur AND above = 1 ) OR (s.ruleDur > s.groupDur AND above = 0)
LIMIT 1
);
END;

Useage of aggregate function but without having clause

Im have the following two tables created:
create table partei(
id int not null primary key ,
name varchar(20),
vorsitzender varchar(20)
);
create table abgeordneter(
name varchar(20),
partei int references partei ,
wahlkreis varchar(20)
)
How can I change this Select-Statement:
SELECT a.Partei
FROM Abgeordneter a, Partei p
WHERE a.Partei = p.ID
GROUP BY a.Partei
HAVING COUNT(a.Name) < 5
Into a statement which doesn't use the having clause, but delivers exactly the same results? Is it even possible?
You can use a subquery an eliminate the JOIN:
SELECT Partei
FROM (SELECT a.Partei, COUNT(*) as cnt
FROM Abgeordneter ap
GROUP BY a.Partei
) a
WHERE cnt < 5;

SQL- How to select data from two different table?

I am working to select data from 2 different table but I can't figured out. If I use INNER JOIN it show noting. Any help are welcome and Thanks.
My First table:
CREATE TABLE P_N(
PN_ID int NOT NULL,
PN VARCHAR (1000),
primary key (PN_ID)
);
My second Table:
CREATE TABLE NAME (
NAME_ID VARCHAR(60) PRIMARY key,
NAME VARCHAR (40)
);
My select code :
SELECT DISTINCT NAME.NAME_ID, PN.PN_ID
FROM NAME
FULL JOIN P_N
ON PN.PN =NAME.NAME_ID;
If I use left or full Join this is the result:
NAME_ID PN_ID
nm0006300 NULL
nm0006400 NULL
nm0006500 NULL
nm0006600 NULL
nm0006700 NULL
AND if I use right join:
NAME_ID PN_ID
null 921691
null 921692
null 921693
null 921694
This is what I want the result to looks like For example:
NAME_ID PN_ID
nm0006300 921691
nm0006400 921692
nm0006500 921693
nm0006600 921694
You don't seem to have a JOIN key. You can add one with ROW_NUMBER():
SELECT n.NAME_ID, PN.PN_ID
FROM (SELECT n.*, ROW_NUMBER() OVER (ORDER BY NAME_ID) as seqnum
FROM NAME n
) n JOIN
(SELECT pn.*, ROW_NUMBER() OVER (ORDER BY PN) as seqnum
FROM P_N pn
) pn
ON PN.seqnum = n.seqnum;
try this
select DISTINCT NAME.NAME_ID, PN.PN_ID
from NAME,P_N as PN
where PN.PN =NAME.NAME_ID

sql join on range giving double row for single record

I needed to join three tables Result, ResultITems and GradeScale. When i do, i get double or two of the same row. I tried Creating the records in sqlfiddle but i get a different correct result. The schema i used in creating the tables in my local sqlite db is exactly the same, which is shown here.
The result table
CREATE TABLE Result (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
SubjectID INTEGER REFERENCES Subjects ( ID ) ON DELETE CASCADE,
SessionID INT REFERENCES Sessions ( ID ),
TermID INT REFERENCES terms ( ID ),
ClassID INTEGER REFERENCES Classes ( ID )
);
The resultItems table
CREATE TABLE ResultItems (
StudentID INTEGER,
ResultID INTEGER REFERENCES Result ( ID ) ON DELETE CASCADE,
Total DECIMAL( 10, 2 )
);
And the gradescale table
CREATE TABLE gradeScale
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
minscore tinyint NOT NULL,
maxscore tinyint NOT NULL,
grade char(1) NOT NULL,
ClassCatID INTEGER
);
now when i execute this query below, i et double row for each record in the ResultItems table
Select ri.studentid, ri.Total,g.grade
From ResultItems ri
left join GradeScale g
ON ( ri.total >= g.minscore AND ri.total <= g.maxscore )
left join Result r on r.id=ri.resultid
WHERE r.sessionid = 4
AND
r.termid = 1
AND
r.classid = 9
ORDER BY grade ASC;
Please see the picture below to see what i mean
![enter image description here][1]
and here is the sql fibble which i created http://sqlfiddle.com/#!7/ffb42/1
why am i getting double rows in the output when i execute in my local db?
From #JotaBet's help, i was able to trace the error to the GradeScale table wihci had double entries for each grade letter for each class group.
So i rewrote the sql to take notice of that
left join GradeScale g
ON ( AND c.classcatid = g.classcatid (ri.total >= g.minscore AND ri.total <= g.maxscore) )

Need assistance with an SQL Query

Here are the associated tables:
movie
(
mvnumb int,
mvtitle char(100),
yrmde int,
mvtype char(9),
crit int,
mpaa char(6),
noms int,
awrd int,
dirnumb int
)
director
(
dirnumb int,
dirname char(36),
dirborn int,
dirdied int
)
My goal is to construct an SQL query that lists the name of the director who has received the maximum number of awards (awrd). I can't seem to get this to work ... any help would be greatly appreciated.. thanks so much.
Something like this (SQL Server):
select top 1 d.dirname,sum(awrd) awrd
from director d
inner join movie m
on m.dirnumb=d.dirnumb
group by d.dirname
order by sum(awrd) desc
Or, on Oracle:
select * from (
select d.dirname, sum(awrd) awards
from director d
inner join movie m
on m.dirnumb=d.dirnumb
group by d.dirname
order by sum(awrd) desc )
where rownum<2;
EDIT: modified Oracle query, as #pilcrow suggested.