Summarize the Table in Sql - sql

I want to join four tables and get total sales(Value*Quantity) for each month.
each transaction have to get monthly wise(July2018)
Example:
Agent_ID Agent Name Total sales(monthly wise)
Agent table
----------
Agent_ID
Agent Name
Agent address
Transaction table
-----------------
Transaction_ID
Transaction_Date(12/7/2018)
Agent_ID
Transation_Status
Transaction Detal table
-----------------------
Transaction_ID
Item_code
Quantity
Item Table
----------
Item_code
Item_name
Value
Pls support for this scenario

Supposing that the Transaction_Date is DATETIME OR TIMESTAMP field, Here is a Mysql query that could give you the desired result.
SELECT SUM(Value * Quantity) as total, DATE_FORMAT(Transaction_Date, '%Y-%M') date
FROM Agent JOIN Transaction USING (Agent_ID)
JOIN Transaction_Detail USING (Transaction_ID)
JOIN Item USING (Item_code)
GROUP BY Agent_ID, date;

Here's your query. Your are trying to sort by month-year.
select concat(DATENAME(month, cast(Transaction_Date as varchar)), year(cast(Transaction_Date as varchar))), sum(t4.Value * t3.Quantity), from table t1
inner join transaction_table t2 on t2.Agent_ID = t1.Agent_ID
inner join transaction_detail_table t3 on t3.Transactdion_ID = t2.Transaction_ID
inner join item_table t4 on t4.Item_code = t3.Item_code
group by concat(DATENAME(month, cast(Transaction_Date as varchar)), year(cast(Transaction_Date as varchar)))

Related

Search for Max Date and return max date item along with other fields for that record

I have three tables:
WorkOrder that contains all of the Work Orders that have been done on MaintItems, (A MaintItem will occur multiple times in the WorkOrder Table)
MaintItems that contains a list of Unique MaintItems,
LastOccu to store the Last Occurrence details from the WorkOrder table of the MaintItem.
To identify the last date that a MaintItem was performed and to populate the LastOccu table with the MaxDate and MaintItem works correctly. The Problem that I have is when I want to update the lastOccu table with the additional WorkOrder Number field, the query then returns all WorkOrders for that MaintItem.
WorkOrder table example:
WorkOrder MaintItem RefDate Reading
1 101 2018/01/30 200
2 103 2018/02/03 1200
3 101 2018/02/04 230
LastOccu table result required:
MaintItem MaxDate WONumber Reading
101 2018/01/30 3 230
103 2018/02/03 2 1200
The Query that I need help with as follows:
INSERT INTO LastOccu ( MaintItem, MaxDate, WONumber, ReadingNo )
SELECT MD.MaintItem, MD.MaxRefDate, MD.WONumber, MD.ReadingNo
FROM
(SELECT MI.MaintItem, MAX(WO.RefDate) AS MaxRefDate, WO.WONumber,
WO.ReadingNo FROM MaintItem AS MI INNER JOIN WorkOrder AS WO ON
MI.MaintItem = WO.MaintItem WHERE WO.RefDate is not null GROUP BY
MI.MaintItem, WO.WONumber, WO.ReadingNo) AS MD;
Also note that I'm using MS Access
Help will be greatly appreciated!
I don't see the necessity to join with MaintItem table. Each workorder should already have a corresponding MaintItem entry, no? If not, then join (is that WorkOrder or WONumber I couldn't understand).
INSERT INTO LastOccu(MaintItem, MaxDate, WONumber, ReadingNo)
SELECT wo.MaintItem, wo.RefDate, wo.Workorder, wo.ReadingNo
FROM WorkOrder wo
INNER JOIN(
SELECT MaintItem, MAX(RefDate) AS MaxRefDate
FROM WorkOrder
WHERE RefDate IS NOT NULL
GROUP BY MaintItem
) AS MD ON wo.MaintItem=MD.MaintItem
AND wo.RefDate=MD.MaxRefDate;
Note: Oops, I missed you changed tag from sql server to MSAccess. That doesn't support ANSI SQL but at least should support this kind of simple ones I assume, so not deleting. (Your sample output doesn't seem to be right, if that is what could be the logic?).
EDIT:
INSERT INTO LastOccu(MaintItem, MaxDate, WONumber, ReadingNo)
SELECT wo.MaintItem, wo.RefDate, wo.Workorder, wo.ReadingNo
FROM WorkOrder wo
INNER JOIN(
SELECT MaintItem, MAX(RefDate) AS MaxRefDate
FROM WorkOrder
WHERE RefDate IS NOT NULL
GROUP BY MaintItem
) AS MD ON wo.MaintItem=MD.MaintItem
AND wo.RefDate=MD.MaxRefDate
where MaintItem in (Select MaintItem from MaintItem);
One way to do this uses a correlated subquery:
INSERT INTO LastOccu ( MaintItem, MaxDate, WONumber, ReadingNo )
SELECT MD.MaintItem, MD.MaxRefDate, MD.WONumber, MD.ReadingNo
FROM WorkOrder as wo INNER JOIN
MaintItem as mi
ON mi.MaintItem = wo.MaintItem
WHERE wo.RefDate = (SELECT MAX(wo2.RefDate)
FROM WorkOrder as wo2
WHERE wo2.MaintItem = wo.MaintItem
);
The filtering on NULL is not important, because NULL values will not pass the filter.

Select Student list which is not in another table with date difference and aggregate function

I have three table i.e. "tblStudents", "tblStudentFee", "tblTransaction". table design is
tblStudents
StudID
Name
FatherName
MobileNO
ClassID
tblStudentFee
StFeeID
StudID
SessionID
FeesID
FeeAmount
Discount
tblTransaction
TransactionID
StFeeID
StudID
TransDate
Amount
Now I want to join these table in a way that final table after join should have student fee data where tblTransaction.TransDate is 30 days old from today and I also want student who is not present in tblTransaction
try this
SELECT
tsf.*
FROM tblStudentFee tsf
inner join tblStudents ts
on tsf.StudID = ts.StudID
left join tblTransaction tt
on tt.StudID = ts.StudID
and tt.StFeeID = ts.StFeeID
where
(
tt.TransactionID is null
or
DATEDIFF(day,TransDate,getdate())=30
)

Concerned with query size using non-unique join conditions

I have a situation at work. I work in housing. We raise orders to houses (so our contractors can go out and repair the houses).
Orders contain one or more jobs. A dwelling has zero, one or more orders raised against it.
This is a brief data definition. I've simplified the tables - but hopefully you get the idea. An order can contain many jobs, and a property can have many orders.
CREATE TABLE dwellings (
id VARCHAR2(10) PRIMARY KEY NOT NULL,
address VARCHAR2(100) NOT NULL
);
CREATE TABLE orders (
id VARCHAR2(10) PRIMARY KEY NOT NULL,
created_by VARCHAR2(10) NOT NULL,
created_on DATE NOT NULL,
dwelling_id VARCHAR2(10) NOT NULL REFERENCES dwellings(id)
);
CREATE TABLE jobs (
id VARCHAR2(10) PRIMARY KEY NOT NULL,
sor_id VARCHAR2(10) NOT NULL,
order_id VARCHAR2(10) NOT NULL REFERENCES orders(id)
);
And populated:
INSERT INTO dwellings VALUES ('00ABC', '2 The Mews House Little Boston London E1 1EE');
INSERT INTO dwellings VALUES ('5H88H', '3 Electric House Snodsbury S1 1IT');
INSERT INTO orders VALUES ('000001-A', 'CSMITH', DATE '2016-03-10', '00ABC');
INSERT INTO orders VALUES ('000002-A', 'CSMITH', DATE '2016-03-11', '00ABC');
INSERT INTO orders VALUES ('000003-A', 'AJONES', DATE '2016-03-16', '00ABC');
INSERT INTO orders VALUES ('000004-A', 'CSMITH', DATE '2016-03-16', '5H88H');
INSERT INTO jobs VALUES ('001', '000AA0', '000001-A');
INSERT INTO jobs VALUES ('002', '123BB0', '000001-A');
INSERT INTO jobs VALUES ('003', '000AA0', '000002-A');
INSERT INTO jobs VALUES ('004', '787XD7', '000003-A');
INSERT INTO jobs VALUES ('005', '000AA0', '000003-A');
INSERT INTO jobs VALUES ('006', '787XD7', '000004-A');
An analyst wants to know agents who are raising orders that are similar to previous orders. The thing under scrutiny is the SOR_ID, which denotes the type of job. Remember, there is one or more job associated with each order. So the task is: produce a report showing orders that contain one or more duplicate job types to previous orders at the property.
The report I'm building will have these column headings.
Agent Name
Order Id
Address
Previous Order Id
Duplicate Job Types
Here is the start of a query that gets there. I haven't executed it against the database because there are 50,000 properties and 100,000 orders and 200,000 jobs. I'm concerned about the size of the table because I'm joining on columns that are not unique.
select * from orders ord
join orders ord2 on ord.dwelling_id = ord2.dwelling_id --shaky
and ord.id <> ord2.id
and ord.created_on - ord2.created_on between 0 and 90
join jobs job on job.order_id = ord.id
join jobs job2 on job2.order_id = ord2.id
where job.sor_id = job2.sor_id
I'm looking for recommendations for how you might refactor this query into something more manageable (without PLSQL). Note that I haven't used LAG / LEAD and I haven't yet used LISTAGG to collapse the job type codes. That will come later. I'm concerned about how expensive the query is at the moment.
Query:
SELECT o.created_by AS agent_name,
d.address,
LISTAGG( o.id, ',' ) WITHIN GROUP ( ORDER BY o.created_on ) AS order_ids,
j.sor_id AS job_type
FROM dwellings d
INNER JOIN orders o
ON ( o.dwelling_id = d.id )
INNER JOIN jobs j
ON ( j.order_id = o.id )
GROUP BY o.created_by, d.address, j.sor_id
HAVING COUNT(1) > 1;
Output:
AGENT_NAME ADDRESS ORDER_IDS JOB_TYPE
---------- -------------------------------------------- ----------------- ----------
CSMITH 2 The Mews House Little Boston London E1 1EE 000001-A,000002-A 000AA0
Lists the jobs with the different order ids that were of the same type and placed by the same agent at the same address. The orders are listed in chronological order within the comma-separated list.
However, if you want it with your headings then you could do:
SELECT *
FROM (
SELECT o.created_by AS agent_name,
o.id,
d.address,
LAG( o.id ) OVER ( PARTITION BY o.created_by, d.address, j.sor_id
ORDER BY o.created_on
) AS previous_order_id,
j.sor_id AS job_type
FROM dwellings d
INNER JOIN orders o
ON ( o.dwelling_id = d.id )
INNER JOIN jobs j
ON ( j.order_id = o.id )
)
WHERE previous_order_id IS NOT NULL;
Which would output:
AGENT_NAME ID ADDRESS PREVIOUS_ORDER_ID JOB_TYPE
---------- ---------- -------------------------------------------- ----------------- ----------
CSMITH 000002-A 2 The Mews House Little Boston London E1 1EE 000001-A 000AA0
If you want to consider multiple agents then you can remove o.created_by from the GROUP BYor PARTITION BY clauses. For the top query you would then need to use LISTAGG to get all the agents. Like this:
SELECT LISTAGG( o.created_by, ',' ) WITHIN GROUP ( ORDER BY o.created_on ) AS agent_name,
d.address,
LISTAGG( o.id, ',' ) WITHIN GROUP ( ORDER BY o.created_on ) AS order_ids,
j.sor_id AS job_type
FROM dwellings d
INNER JOIN orders o
ON ( o.dwelling_id = d.id )
INNER JOIN jobs j
ON ( j.order_id = o.id )
GROUP BY d.address, j.sor_id
HAVING COUNT(1) > 1;
Or, for the second query, like this:
SELECT *
FROM (
SELECT o.created_by AS agent_name,
o.id,
d.address,
LAG( o.id ) OVER ( PARTITION BY d.address, j.sor_id
ORDER BY o.created_on
) AS previous_order_id,
j.sor_id AS job_type
FROM dwellings d
INNER JOIN orders o
ON ( o.dwelling_id = d.id )
INNER JOIN jobs j
ON ( j.order_id = o.id )
)
WHERE previous_order_id IS NOT NULL;
Both the queries would then also output the order with id 000003-A placed by AJONES.
Changes i would try out:
ord.id <> ord2.id : ord2.id < ord.id (not sure if that's applicable for you)
ord.created_on - ord2.created_on between 0 and 90 : ord2.created_on <= ord.created_on and ord2.created_on >= ord.created_on - 90 (not sure if the RDBMS can do that optimization)
Move job.sor_id = job2.sor_id into the ON clause (But the RDBMS will probably do that for you)
select * from orders ord
join orders ord2
on ord2.dwelling_id = ord.dwelling_id
and ord2.id < ord.id
and ord2.created_on <= ord.created_on
and ord2.created_on >= ord.created_on - 90
join jobs job on job.order_id = ord.id
join jobs job2
on job2.order_id = ord2.id
and job2.sor_id = job.sor_id;
Indexes you will need:
orders(dwelling_id, created_on, id)
jobs(order_id, sor_id)

calculating sum from another table using SQL

I have a table (District) have columns (Id - District name) . And another table (delivery) have columns (quantity - district Id). can i have a result like a table with every district name in a column and sum of quantity in other column using sql?
I understand that this question will be closed as this site is not about doing homework
select a.district_name, b.total
from District as a
inner join
(
select district_id, sum(quantity) as total
from delivery
group by district_id
) as b
on a.id = b.district_id
Try below code
SELECT dis.district_name,SUM(del.quantity) as quantity
FROM district as dis
INNER JOIN delivery as del
ON dis.id = del.district_id
GROUP BY del.district_id
you can use this code:
SELECT ID, Name, SUM(Quantity) AS SumOfQuantity
FROM
(
SELECT District.ID, District.Name, Delivery.Quantity
FROM District, Delivery
WHERE District.Id = Delivery.DistrictID
) AS T1
GROUP BY ID, Name

Find the latest date of two tables with matching primary keys

I have two tables tables, each with primary keys for different people and the contact dates in each category.I am trying to find the most recent contact date for each person, regardless of what table its in. For example:
CustomerService columns: CustomerKey, DateContacted
CustomerOutreach columns: CustomerKey, DateContacted
And I'm just trying to find the very latest date for each person.
Use something like this.
You need to combine the two tables. You can do this by a union. There will be duplicates, but you just group by the customerKey and then find the Max DateContacted
SELECT * INTO #TEMP FROM (
SELECT
CustomerKey
, DateContacted
FROM CustomerService CS
UNION
SELECT
CustomerKey
, DateContacted
FROM CustomerOutreach CS
)
SELECT
CustomerKey
, MAX(DateContacted)
FROM #TEMP
GROUP BY
CustomerKey
Join your tables on primary keys and make a conditional projection.
Select cs.CustomerKey,
CASE WHEN cs.DateContacted <= co.DateContacted
THEN co.DateContacted
ELSE cs.DateContacted END
from CustomerService cs inner join CustomerOutreach co
on cs.CustomerKey = co.CustomerKey
I would do something like this.
Select b.customerKey, b.dateContacted
from (
select a.customerKey, a.DateContacted, Row_Number() over (Partition by customerKey order by DateContacted desc) as RN
from (
Select c.customerKey,
case when (s.DateContacted > o.dateContacted) then s.dateContacted else o.datecontacted end as DateContacted
from Customer c
left outer join customerService s on c.customerKey = s.customerKey
left outer join customerOutreach o on c.customerKey = s.customerKey
where s.customerKey is not null or o.customerKey is not null
)a
)b
where b.RN = 1
This solution should take care of preventing the case of having duplicates if both tables have the same max DateContacted.
http://sqlfiddle.com/#!3/ca968/1