I am working on a database project using both Java and SQL with an Oracle Database. I am new at working with databases and new at SQL. My question is: how would I be able to get the customer count and record each of their purchase history on a pivot table? For example, on the following table, I have Lee a total of 3 times, and purchased Item A, Item B, and Item C. Ann is there 3 times as well and purchased Item D, Item E, and Item F. I want to put their name, the number of occurrences and what they purchased on separate pivot table.
Row Customer Purchase_History
1 Lee Item A
2 Lee Item B
3 Lee Item C
4 Ann Item D
5 Ann Item E
6 Ann Item F
I've written some code attempting to do this, but when I compile and run, it will not give me the desired results. Here is my code:
String TableCount = "SELECT J.Row, J.Customer, J.Purchase_History, C.cnt" +
" FROM Table J INNER JOIN(SELECT Customer, count(Customer) as cnt" +
"FROM Table GROUP BY Customer") C ON J.Customer = C.Customer;
ResultSet rs = st.executeQuery(TableCount);
while(rs.next()){
st.executeUpdate("CREATE TABLE IF NOT EXISTS CUSTOMER_COUNT" +
"(TableCount , Purchase_History )");
String InsertIntoTable = String.format("INSERT INTO CUSTOMER_COUNT" +
"("TableCount","Purchase_History")" +
" VALUES ('%s','%s)");
}
What am I doing wrong here? Any help would be greatly appreciated!
Your query logic is fine. You should print out the query before running it. The problem would be these two lines (at least):
" FROM Table J INNER JOIN(SELECT Customer, count(Customer) as cnt" +
"FROM Table GROUP BY Customer") C ON J.Customer = C.Customer;
I assume you really mean:
" FROM Table J INNER JOIN(SELECT Customer, count(Customer) as cnt" +
"FROM Table GROUP BY Customer) C ON J.Customer = C.Customer";
In any case, when you print this out, you'll have the expression cntFROM table. You need a space:
" FROM Table J INNER JOIN(SELECT Customer, count(Customer) as cnt" +
" FROM Table GROUP BY Customer) C ON J.Customer = C.Customer";
But, an easier way to write your query is to use analytic functions:
select J.Row, J.Customer, J.Purchase_History,
count(*) over (partition by customer) as cnt
from table j
Related
I'm performing an analysis on a certain warehouse within a java program using SQL as its database.
I have 3 tables; table1 contains the general details of a products, table2 contains the transaction details of the product in one region i.e. Region A and table 3 contains transaction details of the product in the other region, say Region B.
Table1 - General Details
id itemID itemName Qty category
1 TAG01 Acer Laptops 10 Electronics
2 TAG04 Baking Floor 200 Foods
3 TAG08 Philips Bulbs 700 Electronics
4 TAG109 Sweat Pants 85 Wear
Table2 - details from Region A
id itemID sellDate
1 TAG01 "
2 TAG01 "
3 TAG109 "
4 TAG01 "
Table3 - details from Region B
id itemID sellDate
1 TAG109 "
2 TAG109 "
I want to select category with its Total Qty from Table1 and attach to it the total number of counts of the distinct itemID from Table2 and Table3
Expect results:
id category Qty totalTransactions
1 Electronics 710 3
2 Foods 200sacks -
3 Wear 85 3
This is what I tried and it give satisfying results
String sql = "SELECT category, Qty FROM table1 INNER JOIN (SELECT itemID, COUNT(*) FROM (SELECT itemID FROM table3 union ALL SELECT itemID FROM table2)t GROUP BY itemID)q"
This should give you what you need. I am joining against two sub-queries where each query performs a COUNT per itemId and then the SUM of the two is done in the main query plus the SUM of the Qty column.
LEFT JOIN is used since not all rows in table1 might have rows in the transaction tables.
SELECT category, SUM(Qty), SUM(IFNULL(t3.c3,0) + IFNULL(t2.c2, 0))
FROM table1 t1
LEFT JOIN (SELECT itemId, COUNT(*) c2 FROM table2 GROUP BY itemId) t2 ON t2.itemId = t1.itemID
LEFT JOIN (SELECT itemId, COUNT(*) c3 FROM table3 GROUP BY itemId) t3 ON t3.itemId = t1.itemID
GROUP BY category
I have 4 tables:
CUSTOMER (idCustomer,name,phone,email, markdown)
ORDER (idOrder,day,Customer_idCustomer)
ORDERITEM (idOrderItem, quantity, Order_idOrder, Product_idProduct)
PRODUCT (idProduct,name,price,description).
What would be the query for:
Average customer spending (for each customer) in individual months
Number of ordered items?
I already wrote some queries on this database.
Since I do it for Java application with JDBC, maybe I can split these two queries and make calculation of average separately but what is the best approach? Is there a way how to do it just with two SQL queries?
Thank you for help.
Query I use for price reduction:
String sql = "SELECT c.markdown, SUM(oi.quantity * p.price)
FROM orderitem oi, `order` o, product p, customer c
WHERE c.idCustomer = o.Customer_idCustomer
AND oi.Order_idOrder=o.idOrder
AND oi.Product_idProduct=p.idProduct
AND o.idOrder=" + idOrderValue + "
GROUP BY oi.Order_idOrder";
Look here for database design (ERD)
You want an aggregation query with JOINs. Use proper JOIN syntax! Do not use commas in the FROM clause:
SELECT year(o.day) as yyyy,
month(o.day) as mm,
SUM(oi.quantity * p.price) / COUNT(DISTINCT c.idCustomer) as avg_customer_spending,
SUM(oi.quantity) as num_items
FROM customers c JOIN
orders o
ON c.idCustomer = o.Customer_idCustomer JOIN
orderitem oi
ON oi.Order_idOrder = o.idOrder JOIN
product p
ON oi.Product_idProduct = p.idProduct
GROUP BY year(o.day), month(o.day);
I have the following setup (Java/Hibernate/PostgreSQL):
TeamName {
id: Long;
name: String;
team: Team;
....
}
Series {
id: Long;
season: Season;
dateScheduled: Date;
}
SeriesTeam {
id: Long;
series: Series;
team: TeamName;
}
SeriesTeam {
id: Long;
team: TeamName;
}
What I want to do is do a select of the past n series (say 10) or the next series from the current date. Here's what I have so far:
select s.* from series s
inner join series_teams st on st.series_id = s.id
inner join team_names tn on tn.id = st.team_name_id
where tn.id in (:teamIds) and s.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc
But that is going to get me all the prior series for all teams and I will have to use Java to pick out what I want How would I go about doing what I want? Thanks!
EDIT: For example, say I wanted a limit of 10 per team name, and there are 24 teams, I would want max of 240 records returned to me. (assuming 10 exist before current date)
EDIT2: Here is the code that I want for a single team:
select s. from series s
inner join series_teams st on st.series_id = s.id
where st.team_name_id=85 and s.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc
limit 10
I just need to be able to apply this for all the teams....I don't want to make x SQL calls for every team.
I think this will work. The syntax is in mysql and you can try it at that site the structure they have is similar to yours. you can adjust the limit value to change how many from each employee to return sorted by date. Probably add the current date check there too i guess.
Basically I joined all the needed tables together then created a new column that will tell me if that row is one we should return then added that check in the where clause.
https://www.w3schools.com/sql/trysql.asp?filename=trysql_op_in
SELECT e.employeeid, lastname,orderdate, orderdate in (select orderdate from
orders ord where e.employeeid=ord.employeeid order by orderdate limit 2) as
good FROM Employees as e join orders as o on e.employeeid=o.employeeid where
good=1 order by e.employeeid, o.orderdate;
for your case:
select s.id, s.season_id, s.date_scheduled, st.team_name_id,
s.date_scheduled in (
select s2.date_scheduled from series s2
inner join series_teams st2 on st2.series_id = s2.id
inner join team_names tn2 on tn2.id = st2.team_name_id
where tn.id =tn2.id and s2.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc limit 5
) as foo
from series s
inner join series_teams st on st.series_id = s.id
inner join team_names tn on tn.id = st.team_name_id
where tn.id in (:teamIds) and foo = true
order by st.team_name_id, s.date_scheduled desc
Suppose you have a following JPA query:
select car.year, car.month, count(car) from Car car group by car.year, car.month
Before we query for results, we need to know how many records this query will return (for pagination, UI and so on). In other words we need something like this:
select count(*) from
(select car.year, car.month, count(car)
from Car car group by car.year)
But JPA/EclipseLink does not support subqueries in "from" clause. It there a way around it?
(Of course you can use plain SQL and native queries, but this is not an option for us)
A portable JPA solution:
select count(*) from Car c where c.id in
(select MIN(car.id) from Car car group by car.year, car.month)
You could also go with something like:
select COUNT(DISTINCT CONCAT(car.year, "#", car.month)) from car
but I expect this to be less performant due to operations with textual values.
What about:
select count(distinct car.year) from car
I have another approach to solve this issue . by using my approach you don't need to know the no of rows this query is going to return.
here it is your solution :-
you going to need two variables
1) pageNo (your page no should be 1 for first request to data base and proceeding request it should be incremental like 2 ,3 , 4 5 ).
2) pageSize.
int start = 0;
if(pageNo!=null && pageSize!=null){
start = (pageNo-1) * pageSize;
}else{
pageSize = StaticVariable.MAX_PAGE_SIZE; // default page size if page no and page size are missing
}
your query
em.createquery("your query ")
.setfirstResult(start)
.setMaxResult(pageSize)
.getResultList();
As #chris pointed out EclipseLink supports subqueries. But the subquery can't be the first one in the from-clause.
So I came up with the following workaround which is working:
select count(1) from Dual dual,
(select car.year, car.month, count(car)
from Car car group by car.year) data
count(1) is important as count(data) would not work
You have to add an entity Dual (If your database does not have a DUAL table, create one with just one record.)
This works but I still consider it a workaround that would only work if you allowed to create the DUAL table.
Simply you can use setFirstResult and setMaxResult to set record bound for query ,also use size of list to return count of records that query runs. like this :
Query query = em.createQuery("SELECT d.name, COUNT(t) FROM Department d JOIN
d.teachers t GROUP BY d.name");
//query.setFirstResult(5);
//query.setMaxResult(15); this will return 10 (from 5 to 15) record after query executed.
List<Object[]> results = query.getResultList();
for (int i = 0; i < results.size(); i++) {
Object[] arr = results.get(i);
for (int j = 0; j < arr.length; j++) {
System.out.print(arr[j] + " ");
}
System.out.println();
}
-----Updated Section------
JPA does not support sub-selects in the FROM clause but EclipseLink 2.4 current milestones builds does have this support.
See, http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause
You can probably rewrite the query with just normal joins though.
Maybe,
Select a, size(a.bs) from A a
or
Select a, count(b) from A a join a.bs b group by a
I hope this helps you.
I have never been very good at SQL queries (I've always preferred NoSQL databases, but I need to use a SQL database this time).
I need to research how many seats are sold compared to the amount of total seats in cinema halls. At the moment I can accomplish this using 2 different queries in Hibernate, one for the total amount of seats and the other for the amount of sold seats, and then divising these results.
This is my code :
Double amountOfSoldTickets = ((Long) session.createQuery("select count(*) from Ticket t where t.vertoning.zaal.cinemacomplex.id = :id").
setInteger("id", complex.getId()).list().get(0)).doubleValue();
Double capacity= ((Long) session.createQuery("select sum(z.capaciteit) from Zaal z").list().get(0)).doubleValue();
return amountOfSoldTickets / capacity;
I thought about using a subquery though I have no idea how to do this in hibernate.
If anyone has any idea how to solve this in one query it'd be greatly appreciated.
Some additional info: I let hibernate implicitly join my tables in the first query.
Ticket has a many to one to Vertoning, Vertoning has a many to one to Zaal, Zaal has a many to one to cinemacomplex
I encourage you to learn SQL -- and to learn it on a real database instead of through the HQL interface. HQL is useful for what it does, but it misses on some very important SQL functionality.
I believe the following will work in HQL:
select count(*) as SoldSeats,
(select sum(z.capaciteit) from Zaal z) as Capacity
from Ticket t
where t.vertoning.zaal.cinemacomplex.id = :id;
In just MySQL, you could put these as subqueries in the from clause:
select t.SoldSeats, z.Capacity
from (select count(*) as SoldSeats,
from Ticket t
where t.vertoning.zaal.cinemacomplex.id = :id
) t
(select sum(z.capaciteit) as Capacity
from Zaal z
) z;
Note that if this is inside a loop where you are assigning different values to id, then the whole loop can possibly replaced with SQL.
I suggest you run this query:
Long[] amountOfSoldTicketsToCapacity =
((Long[]) session.createQuery(
"select count(*), z.capaciteit, z.id " +
"from Ticket t " +
"inner join t.vertoning v " +
"inner join v.zaal z " +
"inner join z.cinemacomplex c " +
"where c.id = :id " +
"group by z.capaciteit, z.id "
)
.setInteger("id", complex.getId())
.uniqueResult());
if {
throw new IllegalArgumentException("There are no tickets sold for Zaal#" + complex.getId());
}
double capacity = (amountOfSoldTicketsToCapacity.length != 0) ?
((double) amountOfSoldTicketsToCapacity[0]) / amountOfSoldTicketsToCapacity[1] : 0D;
Doing the division in Java is simpler, as in SQL you'd probably have to CAST one operand to NUMERIC.