SQL AVG statement another table - sql

I'm having trouble with a SQL query. The goal is to see only the certain entries on a specific date (I got this already) which have an average score below 1 in their last 5 home games.
You can see the tables here:
http://dbup2date.uni-bayreuth.de/downloads/bundesliga/Klassendiagramm_Bundesliga.pdf
I have this code so far:
SELECT
A.Spieltag, A.Datum, A.Uhrzeit, B.Name AS Heim
FROM
Spiel AS A
JOIN
Verein AS B ON A.Heim = B.V_ID AND B.Liga = 1
WHERE
Spieltag = 5
HAVING
AVG(SELECT Tore_Heim
FROM Spiel AS A
JOIN Verein AS B
WHEN A.Heim = B.V_ID) < 1
Sorry for my bad English
Thank you

Make sure you group by any =fields that you are not aggregating on when you use HAVING. And you can simplify that HAVING clause since you are already referencing those exact tables in your FROM:
SELECT
A.Spieltag, A.Datum, A.Uhrzeit, B.Name AS Heim
FROM
Spiel AS A
JOIN
Verein AS B ON A.Heim = B.V_ID AND B.Liga = 1
WHERE
Spieltag = 5
GROUP BY A.Spieltag, A.Datum, A.Uhrzeit, B.Name
HAVING
AVG(Tore_Heim) < 1

Related

Grouped / pivot query in SQL

I am looking to find a query to link data from one table to an other table. both tables contain the same order ID and part ID. but one table has 4 lines for every piece. the PRFNAME field should be added in a separated column.
Table 1 : IDBGPL
ID;ORDERID;CNT;NAME1;MATNAME;MATGRID;SURFTLEN;SURFTWIDTH
16385;Project_Name_1;1;Corpuszijde;EG_ED_Px_W1001_ST9_18;0;2146;138
16386;Project_Name_1;1;Corpuszijde;EG_ED_Px_W1001_ST9_18;0;2146;50
16385;Project_Name_2;1;Zijde Rechts;EG_ED_Px_W1001_ST9_18;0;888;519,2
Table 2: IDBPRF
ID;ORDERID;PRFNO;PRFID
16385;Project_Name_1;1;PRF_Verstek_Overmaat_25
16385;Project_Name_1;2;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_1;3;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_1;4;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;1;PRF_Verstek_Overmaat_25
16386;Project_Name_1;2;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;3;PRF_00_Overmaat_25
16386;Project_Name_1;4;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;1;EG_ABS_H3335_ST28_08_75
16385;Project_Name_2;2;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;3;PRF_00
16385;Project_Name_2;4;PRF_EG_ABS_W1000_ST9_2
This is the desired result from the query:
ID;ORDERID;NAME1;Kant 1 (PRFNO = 1);Kant 2 (PRFNO = 2);Kant 3 (PRFNO = 3);Kant 4 (PRFNO = 4)
16385;Project_Name_1;Corpuszijde;PRF_Verstek_Overmaat_25;PRF_EG_ABS_W1000_ST9_2;PRF_EG_ABS_W1000_ST9_2;PRF_EG_ABS_W1000_ST9_2
16386;Project_Name_1;Corpuszijde;PRF_Verstek_Overmaat_25;PRF_EG_ABS_W1000_ST9_2;PRF_00_Overmaat_25;PRF_EG_ABS_W1000_ST9_2
16385;Project_Name_2;Zijde Rechts;EG_ABS_H3335_ST28_08_75;PRF_EG_ABS_W1000_ST9_2;PRF_00;PRF_EG_ABS_W1000_ST9_2
Here is a link to some example data in Excel:
https://rasgroup-my.sharepoint.com/:x:/g/personal/maarten_de_potter_ras-group_eu/Ec-PvcsV5GhFuademkU83JcBiob28FicrUr3Kl9-VkPE7Q?e=sqOYUu
The closest i got to a result was this query, but then I was not able to group the 4 part lnes to one.
enter image description here
SELECT
a.ID AS A_ID ,
a.ORDERID AS A_ORDERID,
b.ID AS B_ID ,
b.ORDERID AS B_ORDERID,
b.NAME1,
(CASE WHEN a.PRFNO = 1 THEN a.PRFID END) AS Kant1,
(CASE WHEN a.PRFNO = 2 THEN a.PRFID END) AS Kant2,
(CASE WHEN a.PRFNO = 3 THEN a.PRFID END) AS Kant3,
(CASE WHEN a.PRFNO = 4 THEN a.PRFID END) AS Kant4
FROM
IDBPRF a, IDBGPL b
WHERE
a.ORDERID = b.ORDERID
AND a.ID = b.ID
Hopefully someone could help me with solving this puzzle.

T-SQL subselect statement is returning all rows instead of limiting to 1 based on subselect

I am trying to return just the first row where the BLOCK_STOP_ORDER = 2. What is wrong with my SQL? Why isn't WHERE SCHEDULE.BLOCK_STOP_ORDER = (SELECT MIN(S1.BLOCK_STOP_ORDER....
working? When I run the subselect on its own it returns the value '2' - doesn't that mean it should then limit the query result to only the row(s) where BLOCK_STOP_ORDER = 2?
SELECT ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID, SCHEDULE.PATTERN_ID, SCHEDULE.BLOCK_STOP_ORDER,
SCHEDULE.SCHEDULED_TIME, GEO_NODE.GEO_NODE_ABBR, TRIP.TRIP_SEQUENCE AS TPST
FROM SCHEDULE
INNER JOIN GEO_NODE ON SCHEDULE.GEO_NODE_ID = GEO_NODE.GEO_NODE_ID
INNER JOIN ROUTE ON SCHEDULE.ROUTE_ID = ROUTE.ROUTE_ID
INNER JOIN TRIP ON SCHEDULE.TRIP_ID = TRIP.TRIP_ID
WHERE (SCHEDULE.CALENDAR_ID = '120221024') AND ROUTE.ROUTE_ABBR = '001'
AND SCHEDULE.ROUTE_DIRECTION_ID = '2' AND SCHEDULE.PATTERN_ID = '270082'
AND TRIP.TRIP_SEQUENCE = '18600'
AND SCHEDULE.BLOCK_STOP_ORDER =
(SELECT MIN(S1.BLOCK_STOP_ORDER)
FROM SCHEDULE S1
WHERE SCHEDULE.CALENDAR_ID = S1.CALENDAR_ID
AND SCHEDULE.ROUTE_ID = S1.ROUTE_ID
AND SCHEDULE.ROUTE_DIRECTION_ID = S1.ROUTE_DIRECTION_ID
AND SCHEDULE.PATTERN_ID = S1.PATTERN_ID
AND SCHEDULE.SCHEDULED_TIME = S1.SCHEDULED_TIME
AND SCHEDULE.GEO_NODE_ID = S1.GEO_NODE_ID
AND SCHEDULE.BLOCK_STOP_ORDER = S1.BLOCK_STOP_ORDER
AND SCHEDULE.TRIP_ID = S1.TRIP_ID
)
GROUP BY ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID,
SCHEDULE.PATTERN_ID, SCHEDULE.SCHEDULED_TIME,
GEO_NODE.GEO_NODE_ABBR, SCHEDULE.BLOCK_STOP_ORDER, TRIP.TRIP_SEQUENCE
ORDER BY ROUTE.ROUTE_ABBR, SCHEDULE.ROUTE_DIRECTION_ID, TRIP.TRIP_SEQUENCE
Results:
ROUTE_ABBR
ROUTE_DIRECTION_ID
PATTERN_ID
BLOCK_STOP_ORDER
SCHEDULED_TIME
GEO_NODE_ABBR
TPST
001
2
270082
2
18600
1251
18600
001
2
270082
3
18600
1346
18600
001
2
270082
5
18720
1123
18600
001
2
270082
6
18720
11372
18600
001
2
270082
4
18720
1570
18600
001
2
270082
8
18780
11373
18600
This is probably better solved with the row_number() windowing function:
SELECT *
FROM (
SELECT DISTINCT r.ROUTE_ABBR, s.ROUTE_DIRECTION_ID, s.PATTERN_ID, s.BLOCK_STOP_ORDER,
s.SCHEDULED_TIME, g.GEO_NODE_ABBR, t.TRIP_SEQUENCE AS TPST,
row_number() over (order by SCHEDULE.BLOCK_STOP_ORDER) rn
FROM SCHEDULE s
INNER JOIN GEO_NODE g ON s.GEO_NODE_ID = g.GEO_NODE_ID
INNER JOIN ROUTE r ON s.ROUTE_ID = r.ROUTE_ID
INNER JOIN TRIP t ON s.TRIP_ID = t.TRIP_ID
WHERE s.CALENDAR_ID = '120221024' AND r.ROUTE_ABBR = '001'
AND s.ROUTE_DIRECTION_ID = '2' AND s.PATTERN_ID = '270082'
AND t.TRIP_SEQUENCE = '18600'
) t1
WHERE rn=1
ORDER BY t1.ROUTE_ABBR, t1.ROUTE_DIRECTION_ID, t1.TRIP_SEQUENCE
The problem with the original is the name SCHEDULE. For the full version of the query, the subquery is matching the name in the nested select with the instance of the table from the outer select. This correlates the results of the inner table with the outer, so only the item from that row of the outer table is eligible.
When you run the inner query by itself, separate from the outer query, there is only the one instance of the table. In that situation the WHERE conditions are matching the table to itself — they are always true — and you just get the smallest value of all the rows: 2.
This is why you should ALWAYS give ALL the tables in your queries an alias, and ONLY reference them by that alias (as I did in my answer). Do this, and the MIN() version can work... but will still be slower and more code than using row_number().
Finally, the use of DISTINCT / GROUP BY with every SELECT column is usually an indicator you don't fully understand the JOIN relationships used in the query, and in at least one case the join conditions are not sufficiently selective. I'd hesitate to move a query like that to production, even if it seems to be working, though I confess most of us have done it at some point anyway.

Make sum of num_importe by the entidad code sql

My code:
select distinct entidad, sum(cast(num_importe as float))
from envio_remesa
inner join remesa
on envio_remesa.id = remesa.envio_remesa_id
where remesa.envio_remesa_id = 3 and remesa.tipo_doc='201';
The case is that for example I have two different "entidades"(suppose 18 and 21, but it can be any number), and I want to group in two different records the sum of the "num_importe" for the "entidad" 18, and the sum of the "num_importe" for the "entidad" 21.How could I do it?
What I want to come out:
entidad num_importe
18 92.300,00
21 56.000,20
432 120.000,32
12 12.232,12
you shoud use group by (by the way, distinct is useless here)
select entidad, sum(cast(num_importe as float))
from envio_remesa
inner join remesa
on envio_remesa.id = remesa.envio_remesa_id
where remesa.envio_remesa_id = 3 and remesa.tipo_doc='201'
group by entidad;
You can use aggregation:
select entidad, sum(cast(num_importe as float))
from envio_remesa er inner join
remesa r
on er.id = r.envio_remesa_id
where r.envio_remesa_id = 3 and r.tipo_doc = '201'
group by entidad;
Note: You should qualify entidad and num_importe so it is clear what table they come from.
Also, I added table aliases into the query. They make the query easier to write and to read.

SQL to select parent that contains child specific value

I am actually creating a crystal reports v12 (2008) report but can't find the method, using Crystal, to extract the following. I thought if someone might answer in SQL language, I could piece it together.
2 Tables: hbmast, ddmast
SELECT hbmast.custno, hbmast.id, ddmast.name, ddmast.status
WHERE hbmast.custno = ddmast.custno
GROUP BY hbmast.id
pseudo code::show all hbmast values that have ddmast.status = '2'
Sample output:
J0001, 111222, PAUL JONES, 1
111222, PAUL JONES, 2
111222, PAUL JONES, 1
K0001, 555333, PETER KING, 3
555333, PETER KING, 1
I would like to have Paul show on the report with all child records but Peter should not be returned on the report since he has no child records with '2' for ddmast.status field.
Thanks for the help
I think you're looking for this:
select hb.custno, hb.id, dd.name, dd.status from hbmast hb
join ddmast dd on hb.custno = dd.custno
where hb.custno in (
select custno from ddmast
where status = '2'
)
Let me know if this returns your expected result.
The way to achieve this in Crystal would be to have your hb and dd tables then a second alias of the dd table.
So you would filter your dd alias table where status = 2 then join to your hb table and back to your dd table (not the alias). The SQL would end up looking like:
select hb.custno, hb.id, dd.name, dd.status from hbmast hb
inner join ddmast dd on hb.custno = dd.custno
inner join ddmast dd2 on hb.custno = dd2.custno
where dd2.status = '2'
Andomar makes a valid point about duplicate records appearing if there is more than 1 record per group with a status of 2. If that is the case you can either group by primary key and show row information at group footer level OR use a sql expression with a subquery in your selection formula instead of the double join method.
SQL Expression: (select count(*) from ddmast where custno = "hbmast.custno" and status = '2')
Then record selection expert: {%sqlexpression} > 0
And a different way to get the same...
SELECT hb.custno, hb.id, dd.name, dd.status
FROM hbmast hb
INNER join ddmast dd
on hb.custno = dd.custno
INNER JOIN DDMAST2 DD2
on DD2.custNo = HB.custNo
AND DD2.Status='2'

how to write this query using joins?

i have a table campaign which has details of campaign mails sent.
campaign_table: campaign_id campaign_name flag
1 test1 1
2 test2 1
3 test3 0
another table campaign activity which has details of campaign activities.
campaign_activity: campaign_id is_clicked is_opened
1 0 1
1 1 0
2 0 1
2 1 0
I want to get all campaigns with flag value 3 and the number of is_clicked columns with value 1 and number of columns with is_opened value 1 in a single query.
ie. campaign_id campaign_name numberofclicks numberofopens
1 test1 1 1
2 test2 1 1
I did this using sub-query with the query:
select c.campaign_id,c.campaign_name,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofclicks,
(SELECT count(campaign_id) from campaign_activity WHERE campaign_id=c.id AND is_clicked=1) as numberofopens
FROM
campaign c
WHERE c.flag=1
But people say that using sub-queries are not a good coding convention and you have to use join instead of sub-queries. But i don't know how to get the same result using join. I consulted with some of my colleagues and they are saying that its not possible to use join in this situation. Is it possible to get the same result using joins? if yes, please tell me how.
This should do the trick. Substitute INNER JOIN for LEFT OUTER JOIN if you want to include campaigns which have no activity.
SELECT
c.Campaign_ID
, c.Campaign_Name
, SUM(CASE WHEN a.Is_Clicked = 1 THEN 1 ELSE 0 END) AS NumberOfClicks
, SUM(CASE WHEN a.Is_Opened = 1 THEN 1 ELSE 0 END) AS NumberOfOpens
FROM
dbo.Campaign c
INNER JOIN
dbo.Campaign_Activity a
ON a.Campaign_ID = c.Campaign_ID
GROUP BY
c.Campaign_ID
, c.Campaign_Name
Assuming is_clicked and is_opened are only ever 1 or 0, this should work:
select c.campaign_id, c.campaign_name, sum(d.is_clicked), sum(d.is_opened)
from campaign c inner join campaign_activity d
on c.campaign_id = d.campaign_id
where c.flag = 1
group by c.campaign_id, c.campaign_name
No sub-queries.
Hmm. Is what you want as simple as this? I'm not sure I'm reading the question right...
SELECT
campaign_table.campaign_id, SUM(is_clicked), SUM(is_opened)
FROM
campaign_table
INNER JOIN campaign_activity ON campaign_table.campaign_id = campaign_activity.campaign_id
WHERE
campaign_table.flag = 1
GROUP BY
campaign_table.campaign_id
Note that with an INNER JOIN here, you won't see campaigns where there's nothing corresponding in the campaign_activity table. In that circumstance, you should use a LEFT JOIN, and convert NULL to 0 in the SUM, e.g. SUM(IFNULL(is_clicked, 0)).
I suppose this should do it :
select * from campaign_table inner join campaign_activity on campaign_table.id = campaign_activity.id where campaign_table.flag = 3 and campaign_activity.is_clicked = 1 and campaign_activity.is_opened = 1
Attn : this is not tested in a live situation
The SQL in it's simplest form and most robust form is this: (formatted for readability)
SELECT
campaign_table.campaign_ID, campaign_table.campaign_name, Sum(campaign_activity.is_clicked) AS numberofclicks, Sum(campaign_activity.is_open) AS numberofopens
FROM
campaign_table INNER JOIN campaign_activity ON campaign_table.campaign_ID = campaign_activity.campaign_ID
GROUP BY
campaign_table.campaign_ID, campaign_table.campaign_name, campaign_table.flag
HAVING
campaign_table.flag=1;