Error while using group by - sql

In table A I have the dates, and in B I have the order numbers.
In both tables I have a common field called order Id.
I just have a simple goal to fetch the number of orders on each date[ as in 1st, 2nd ..]
Here is what I have tried as I dont want to use joins or views.
select
A.date_of_order,
count(B.order_number)
from A, B
where A.order_id=B.order_id;
group by A.date_of_order
I am getting the following error. Probably making some trivial error. Thanks in advance
Update:
After taking into consideration Dmitri and rafa s suggestions, I get the table as:
23-FEB-14 1
23-FEB-14 1
23-FEB-14 2
23-FEB-14 2
23-FEB-14 2
07-MAR-14 2
07-MAR-14 4
07-MAR-14 1
07-MAR-14 5
02-MAR-14 1
02-MAR-14 1
As I said my requirement is very simple, just get it as
23-Feb-14 10[i.e. all the orders placed on this date]
07-Mar-14 13
02-mar-14 2

WHERE should be put before GROUP BY:
select A.date_of_order,
count(B.order_number)
from A, B
where A.order_id = B.order_id -- <- possible, but join will be better here
group by A.date_of_order
If you want a condition after GROUP BY you should use HAVING
select A.date_of_order,
count(B.order_number)
from A, B
where A.order_id = B.order_id
group by A.date_of_order
having count(B.order_number) < 3 -- having demo

The WHERE clause must to be before of the GROUP BY clause.
Use TRUNC(date) to get rid of the time so the GROUP BY will work as expected.
SELECT TRUNC(A.date_of_order), COUNT(B.order_number)
FROM A, B
WHERE A.order_id=B.order_id
GROUP BY TRUNC(A.date_of_order)
Anyway it is recommended to use the ANSI-standard SQL JOIN clause instead.
SELECT TRUNC(A.date_of_order), COUNT(B.order_number)
FROM A INNER JOIN B ON A.order_id = B.order_id
-- (WHERE conditions here)
GROUP BY TRUNC(A.date_of_order)
-- (HAVING conditions here)

The possible reasons could be that
1) Dates have timestamp, in that case following query would be helpful:
select
trunc(A.date_of_order),
count(B.order_number)
from A, B
where A.order_id=B.order_id
group by trunc(A.date_of_order);
2) Since in your sample data, you already have count against the dates, you need to take sum instead of count for your query
select
A.date_of_order,
sum(B.order_number)
from A, B
where A.order_id=B.order_id
group by A.date_of_order;
3) Or could be both, in that case you can try
select
trunc(A.date_of_order),
sum(B.order_number)
from A, B
where A.order_id=B.order_id
group by trunc(A.date_of_order);

I don't see why you need to join to that other table at all. Try just running:
select date_of_order, count(order_id) from tbl_a group by date_of_order
Your question states that table A contains rows for each order ID and date, and all you want to do is count the number of orders by date.

Related

Grouping records on consecutive dates

If I have following table in Postgres:
order_dtls
Order_id Order_date Customer_name
-------------------------------------
1 11/09/17 Xyz
2 15/09/17 Lmn
3 12/09/17 Xyz
4 18/09/17 Abc
5 15/09/17 Xyz
6 25/09/17 Lmn
7 19/09/17 Abc
I want to retrieve such customer who has placed orders on 2 consecutive days.
In above case Xyz and Abc customers should be returned by query as result.
There are many ways to do this. Use an EXISTS semi-join followed by DISTINCT or GROUP BY, should be among the fastest.
Postgres syntax:
SELECT DISTINCT customer_name
FROM order_dtls o
WHERE EXISTS (
SELEST 1 FROM order_dtls
WHERE customer_name = o.customer_name
AND order_date = o.order_date + 1 -- simple syntax for data type "date" in Postgres!
);
If the table is big, be sure to have an index on (customer_name, order_date) to make it fast - index items in this order.
To clarify, since Oto happened to post almost the same solution a bit faster:
DISTINCT is an SQL construct, a syntax element, not a function. Do not use parentheses like DISTINCT (customer_name). Would be short for DISTINCT ROW(customer_name) - a row constructor unrelated to DISTINCT - and just noise for the simple case with a single expression, because Postgres removes the pointless row wrapper for a single element automatically. But if you wrap more than one expression like that, you get an actual row type - an anonymous record actually, since no row type is given. Most certainly not what you want.
What is a row constructor used for?
Also, don't confuse DISTINCT with DISTINCT ON (expr, ...). See:
Select first row in each GROUP BY group?
Try something like...
SELECT `order_dtls`.*
FROM `order_dtls`
INNER JOIN `order_dtls` AS mirror
ON `order_dtls`.`Order_id` <> `mirror`.`Order_id`
AND `order_dtls`.`Customer_name` = `mirror`.`Customer_name`
AND DATEDIFF(`order_dtls`.`Order_date`, `mirror`.`Order_date`) = 1
The way I would think of it doing it would be to join the table the date part with itselft on the next date and joining it with the Customer_name too.
This way you can ensure that the same customer_name done an order on 2 consecutive days.
For MySQL:
SELECT distinct *
FROM order_dtls t1
INNER JOIN order_dtls t2 on
t1.Order_date = DATE_ADD(t2.Order_date, INTERVAL 1 DAY) and
t1.Customer_name = t2.Customer_name
The result you should also select it with the Distinct keyword to ensure the same customer is not displayed more than 1 time.
For postgresql:
select distinct(Customer_name) from your_table
where exists
(select 1 from your_table t1
where
Customer_name = your_table.Customer_name and Order_date = your_table.Order_date+1 )
Same for MySQL, just instead of your_table.Order_date+1 use: DATE_ADD(your_table.Order_date , INTERVAL 1 DAY)
This should work:
SELECT A.customer_name
FROM order_dtls A
INNER JOIN (SELECT customer_name, order_date FROM order_dtls) as B
ON(A.customer_name = B.customer_name and Datediff(B.Order_date, A.Order_date) =1)
group by A.customer_name

Oracle Left Join not returning all rows

I am using the following CTE. The first part collects all unique people and the second left joins the unique people with events during a particular time frame. I am expecting that all the rows be returned from my unique people table even if they don't have an event within the time frame. But this doesn't appear to be the case.
WITH DISTINCT_ATTENDING(ATTENDING) AS
(
SELECT DISTINCT ATTENDING
FROM PEOPLE
WHERE ATTENDING IS NOT NULL
), -- returns 62 records
EVENT_HISTORY(ATTENDING, TOTAL) AS
(
SELECT C.ATTENDING,
COUNT(C.ID)
FROM DISTINCT_ATTENDING D
LEFT JOIN PEOPLE C
ON C.ATTENDING = D.ATTENDING
AND TO_DATE(C.DATE, 'YYYYMMDD') < TO_DATE('20140101', 'YYYYMMDD')
GROUP BY C.ATTENDING
ORDER BY C.ATTENDING
)
SELECT * FROM EVENT_HISTORY; -- returns 49 rows
What am I doing wrong here?
Jonny
The problem is inthe column "C.ATTENDING", just change for "D.ATTENDING"
SELECT D.ATTENDING,
COUNT(C.ID)
FROM DISTINCT_ATTENDING D
LEFT JOIN PEOPLE C
ON C.ATTENDING = D.ATTENDING
AND TO_DATE(C.DATE, 'YYYYMMDD') < TO_DATE('20140101', 'YYYYMMDD')
GROUP BY D.ATTENDING
ORDER BY D.ATTENDING
Your query seems too complicated. I think the following does the same thing:
SELECT P.ATTENDING,
SUM(CASE WHEN TO_DATE(P.DATE, 'YYYYMMDD') < TO_DATE('20140101', 'YYYYMMDD')
THEN 1 ELSE 0 END)
FROM PEOPLE P
WHERE P.ATTENDING IS NOT NLL
GROUP BY P.ATTENDING
ORDER BY P.ATTENDING ;
Your problem is that you are aggregating by a column in the second table of a left join. This is NULL when there is no match.

Recursive calculation in SQL (Oracle)

I'm having a tough time finding a solution to ETL some data into my resulting table. I think I cannot accomplish this using pure SQL and need to use PL-SQL due to the looping. Could the sql gurus help me go towards the right direction or provide some pointers to solve this problem?
Here's the scenario:
Tables: TABLEA and TABLEB.
Steps:
Group records in TABLEA by A_CD and SUM the A_AMT FIELD. (Lets assume A_FLAG is always same for any A_CD.). Lets call the grouped resultset as TABLEA_GRP (This is not a table, it is a grouped query).
Pick a row from TABLEB and if B_FLG is 'N' then pick all rows in TABLEA_GRP where A_FLG is 'N'. If the B_FLG is 'Y' then pick all rows in TABLEA_GRP.
Starting first record of rows picked in step 2, calculate the ratio of its TOTAL_AMT to SUM of ALL TOTAL_AMT for the selected rows. Multiply the ratio to B_AMT and add resulting amount to the rows TOTAL_AMT and store in RESULTING_AMT. Repeat this calculation for all rows picked in step 2.
Repeat step 2 and 3, now using the starting TOTAL_AMT VALUE from the RESULTING_AMT value from previous calculation of the same A_CD.
RESULTING _RATIO field is not needed to be saved, it is just given for demo purpose. How would you do this?
Basically I want to get data in RESULTING_TABLE from TABLEA and TABLEB
Could anyone help? Thanks a lot in advance for any guidance.
EDIT: I added A_DATE and B_DATE for supporting join between the two tables. For simplicity you can just do A.A_DATE = B.B_DATE, example this basic join:
SELECT
A.A_CD,
SUM(A.A_AMT) AS TOTAL_AMT,
A.A_FLAG,
A.A_DATE,
B.B_ID,
B.B_AMT,
B.B_FLAG
FROM
TABLEA A
JOIN TABLEB B
ON A.A_DATE = B.B_DATE
GROUP BY
A.A_CD,
A.A_FLAG,
A.A_DATE,
B.B_ID,
B.B_AMT,
B.B_FLAG
;
Okay I think I've got the solution. The numbers are a bit different to yours, but I'm fairly sure mine is doing what you want. We can do everything in steps 1 & 2 using a single query (main_sql). 3 and 4 have to be done using a recursive statement (recur_sql).
with main_sql as (
select a.*,
b.*,
sum(a_amt) over (partition by b_id) as cd_amt,
rank() over (partition by a_cd order by b_id) as rnk
from (select a_cd, a_flag, sum(a_amt) as a_amt
from tablea
group by a_cd, a_flag) a,
tableb b
where a.a_flag = case when b.b_flag = 'Y' then a.a_flag else b.b_flag end
order by b_id, a_cd
),
recur_sql (a_cd, b_id, total_amt, cd_amt, resulting_ratio, resulting_amt, rnk) as (
select m.a_cd,
m.b_id,
m.a_amt as total_amt,
m.cd_amt, m.a_amt / m.cd_amt as resulting_ratio,
m.a_amt + (m.a_amt / m.cd_amt * m.b_amt) as resulting_amt,
rnk
from main_sql m
where rnk = 1
union all
select m.a_cd,
m.b_id,
r.resulting_amt as total_amt,
m.cd_amt,
r.resulting_amt / m.cd_amt as resulting_ratio,
r.resulting_amt + (r.resulting_amt / m.cd_amt * m.b_amt) as resulting_amt,
m.rnk
from recur_sql r,
main_sql m
where m.rnk > 1
and r.a_cd = m.a_cd
and m.rnk - 1 = r.rnk
)
select a_cd, b_id, total_amt, resulting_ratio, resulting_amt
from recur_sql
order by 2, 1

SQL Query Support

I have a transaction table, i want to extract those transactions from the table whose time difference is of 2 hours and transactions are performed in 2 different countries.
I have written the following query but the problem is that it is fetching those transactions as well whose countries are same.
Query is:
SELECT DISTINCT b.*
FROM TRANSACTION_TABLE b, TRANSACTION_TABLE a
WHERE
b.CARD IN (SELECT b.CARD
FROM TRANSACTION_TABLE b, TRANSACTION_TABLE a
WHERE b.TYPE_TXN IN ('21')
AND b.RESPONSE_TXN='00'
AND b.DATETIME_TXN BETWEEN DATEADD(hh,-2,GETDATE()) AND GETDATE()
AND b.CARD=a.CARD
AND b.COUNTRY<>a.COUNTRY
GROUP BY B.CARD
HAVING COUNT(B.CARD)>1 )
AND b.TYPE_TXN in ('21')
AND b.RESPONSE_TXN='00'
AND b.DATETIME_TXN BETWEEN DDATEADD(hh,-2,GETDATE()) AND GETDATE()
AND b.CARD=a.CARD
AND b.COUNTRY<>a.COUNTRY
Please guide.
Thanks
It looks that you should put something like that:
select A.*
from Transaction_Table A,
Transaction_Table B
where -- both transaction should have the same CARD
(A.Card = B.Card) and
-- ... But different countries
-- In order to prevent duplicates > instead of <>
(A.Country > B.Country) and
-- Time difference btw A and B should be less than 2 hours
-- NB! DMBS dependent! (Oracle version implemented)
((Abs(A.DateTime_Txn - B.DateTime_Txn) < 2 / 24) and
-- Other transaction filters
(A.Type_TXN in ('21')) and
(B.Type_TXN in ('21')) and
(A.Response_TXN = '00') and
(B.Response_TXN = '00')

Select from derived table sql exception

I'm trying to execute a select statement from derived table as follows in MSSQL SERVER 2005:
The problem I try to solve is that there are duplicate rows but they differ in DATE field by seconds but i take minutes into account for example
ID DATE
1 08:20:00
1 08:20:01
2 09:21:00
5 10:00:00
5 10:00:01
I want to take DISTINCT values of ID's, and order by DATE but as i order by date I need to include DATE field. So i cant select distinctly on one column.
Derived table query (works by itself perfectly retrieving duplicates)
SELECT p.[SICIL] AS ID, h.[ZAMAN_TRH] AS ZAMAN_TRH
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2 AND
(p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL])
ORDER BY h.[ZAMAN_TRH] DESC
The query that uses the derived table:
SELECT DISTINCT [SICIL]
FROM ( SELECT p.[SICIL] AS SICIL, h.[ZAMAN_TRH] AS ZAMAN_TRH
FROM [RF_BIO].[dbo]. [PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2 AND
(p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL]) ORDER BY h.[ZAMAN_TRH] DESC ) AS LAST
This gets me sql exception in Java
java.sql.SQLException:
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:372)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2893)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2335)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:638)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java:505)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeQuery(JtdsStatement.java:1427)
Thank you for your help.
Use GROUP BY clause with aggregate function in the ORDER BY clause
SELECT p.[ID] AS ID
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[DATE] > '2013-05-27T00:00:00.000' AND h.[YON]= 2
AND (p.[KART] = h.[KART] OR p.[ID]= h.[ID])
GROUP BY p.[ID]
ORDER BY MAX(h.[DATE]) DESC
Simple demo on SQLFiddle
SELECT p.[SICIL] AS SICIL
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2
AND (p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL])
GROUP BY p.[SICIL]
ORDER BY MAX(h.[ZAMAN_TRH]) DESC
Plan Diagram