When i run the below written procedure, the returned result set which i get is like
But Actually according to the scenario, what i want is that I want a single record against the #ContractId parameter. So, I want to merge the rows which my result set returns.
PS: This image shows only few columns, there also exists some other columns which have different values.
This is My Procedure:
ALTER PROCEDURE [dbo].[sp_Tbl_Contract_SearchOne]
-- Add the parameters for the stored procedure here
#ContractID int
AS
BEGIN
select
tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
CountName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
TotalQty,
Vans,
UnitPrice,
Amount
from tbl_Contract
inner join tbl_CountDetail
on
tbl_CountDetail.ContractID = Tbl_Contract.ContractID
inner join tbl_Count tcount
on
tcount.CountID = tbl_CountDetail.CountID
INNER JOIN Tbl_Item
on Tbl_Contract.ItemID = Tbl_Item.ItemID
INNER JOIN Tbl_Brand
on Tbl_Contract.BrandID = Tbl_Brand.BrandID
INNER JOIN Tbl_Seller
on Tbl_Contract.SellerID = Tbl_Seller.SellerID
INNER JOIN Tbl_Buyer
on Tbl_Contract.BuyerID = Tbl_Buyer.BuyerID
INNER JOIN Tbl_CountryFrom
ON Tbl_Contract.CountryFromID=Tbl_CountryFrom.CountryFromID
INNER JOIN Tbl_CountryTo
ON Tbl_Contract.CountryToID = Tbl_CountryTo.CountryToID
inner join tbl_CostUnit
on Tbl_Contract.CostUnitID = tbl_CostUnit.CostUnitID
where Tbl_Contract.ContractID = 1
and Tbl_Contract.IsDeleted = 0 and tbl_CountDetail.IsDeleted = 0
END
It depends what you want to do with the CountName field (the only value that differs between the two) but in theory you could just put it through an aggregation using GROUP BY (If you excluded CountName) or if you wanted to include CountName then maybe PIVOT would do the job.
This falls under aggregation, quite often aggregation means doing an operation (sum, average, standard deviation) on th rows you want to compress into a single row. For example, if your data consisted off number of cookie sales per person per day:
day person sales
======================
1 Bob 5
1 Jane 8
2 Bob 2
2 Jane 10
And you wanted to see over all days what the total sales per person is, you would select person and the sum(sales) grouping by the person
select
person
sum(sales)
from salesData
group by person
Your case is somewhat less standard, in that you are trying to aggregate a filed which is character-based, or alphanumeric. This is fine, sort of, in that there are some aggregations which will work with a character-field. MIN will still work, as wil MAX - returning the first and last field respectively.
ie, doing a min over the set a,b,c will return a as it is first (Minimum ordered by string ordering rules). You seem to have some other numeric fields (Amount,UnitPrice,TotalQty) - these you can pick the correct aggregation for - I suspect SUM is most likely
So you could do this:
select
tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
MIN(CountName) as FirstCountName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
SUM(TotalQty) AS SumTotalQuantity,
Vans,
SUM(UnitPrice) as TotalUnitPrice,
SUM(Amount) AS TotalAmount
from tbl_Contract
[...snip...]
group by tbl_Contract.ContractID,
KeyWinCountNumber,
ItemName,
BrandName,
SellerName,
BuyerName,
ContractNumber,
ContractDate,
CountryFromName,
CountryToName,
Vans
This will now return 1 row, where FirstCountName has the value Count1 502 as this is the first (min) value from the aggregated fields.
Related
I have a query in MySQL designed with multi JOINs.
But the sum total value is different if I use a Group or just one total value.
If I run the query like below I get e.b. 3 lines with the correct calculated price (price*tax_amount).
But if I don't use Group because I want just the overall total the result is different. I guess because the query use the average tax amount instead of the correct amount for each item.
Do you have any idea how I can fix this?
Table:
contracts (contractID, some more data)
objects (objectID, contractID, price, taxID)
tax (taxID, tax_amount)
Query (works):
SELECT SUM(price*tax_amount) AS t_price
FROM contracts
JOIN objects
ON contracts.contractID = objects.contractID
JOIN tax
ON tax.taxID = objects.taxID
GROUP BY contracts.contractID
Result:
233.44 / 345.33 / 22.11
Query (Not work):
SELECT SUM(price*tax_amount) AS t_price
FROM contracts
JOIN objects
ON contracts.contractID = objects.contractID
JOIN tax
ON tax.taxID = objects.taxID
Result: 527.33
I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group
I have 2 tables, one containing tickets and the other routes. I want to produce 2 attributes, flight_DATE and route_CODE, for the greatest numbers of tickets sold. Since there is no attribute that stores the number of tickets sold I have to perform a query finding the max() on the number of count(ticket_ID), as each ticket_ID represents a ticket sold... right? I have no actual database to try this out so that's my query:
SELECT routes.ROUTE_CODE , tickets.FLIGHT_DATE
FROM routes JOIN tickets ON routes.ROUTE_CODE = tickets.ROUTE_CODE
WHERE count(ticket.TICKET_ID) = (
SELECT max(count(ticket.TICKET_ID)
)
I am not so confident with SQL so is this even correct??? thanks in advance!
The idea behind your query is correct, but you wrote the max calculation without a level, so you will get the count of all the tickets sold.
You also cannot put in your where clause a condition on an aggregated column (as you did with count(ticket.TICKET_ID); that kind of condition goes to the having clause.
This one should do what you need
SELECT ROUTE_CODE, FLIGHT_DATE
JOIN tickets
GROUP BY ROUTE_CODE , FLIGHT_DATE
HAVING count(tickets.TICKET_ID) = ( /*filter the row with count = max count */
SELECT max(CNT) /* get the max of the counts */
FROM (
SELECT count(TICKET_ID) as CNT /* get the counts at desired levels */
FROM tickets
GROUP BY FLIGHT_DATE, ROUTE_CODE
)
)
I removed the join with routes table because the only column you were using (ROUTE_CODE) is available on the tickets table too, but that may be useful if you want to select more data from that table and definitely was not an error.
BTW, if you don't have a database available for testing, you can try your queries on sites like rextester
today I'm fighting with MySQL: I've got two tables, that contain records like that (actually there are more columns, but I don't think it's relevant):
Table Metering:
id, value
1000, 0.117
1000, 0.689
1001, 0.050
...
Table Res (there is no more than one record per id in this table):
id, number_residents
1001, 2
...
I try to get results in the following format:
number_residents, avg, count(id)
2, 0.1234, 456
3, 0.5678, 567
...
In words: I try to find out the average of the value-fields with the same number_residents. The id-field is the connection between the two tables. The count(id)-column should show how many ids have been found with that number_residents. The query I could come up with was the following:
select number_residents,count(distinct Metering.id),avg(value)
from Metering, Res
where Metering.id = Res.id
group by number_residents;
The results look like what I searched for but when I tried to validate them I became insecure. I tried it without the distinct at first but that leads to too high values in the count-column of the results.
Is my statement right to get what I want? I thought it might have to to something with the order of execution like asked here, but I actually can't find any official documentation on that...
Thanks for helping!
Judging by the table names, Res is the "parent" table and Metering us the "child" table - that is there are 0-n meterings for each residence.
You have use "old school" joins (and I mean old - the join syntax has been around for 25 years now), which are inner joins, meaning residences without meterings won't participate in the results.
Use an outer join:
select
number_residents,
count(distinct r.id) residences_count,
avg(value) average_value
from Res r
left join Metering m on m.id = r.id
group by number_residents
Although meterings.id = res.id, with a left join counting them may produce different results: I've changed the count to count residences, which for a left join means residences that don't have meterings still count.
Now, nulls (which are what you get from a left-joined table that doesn't have a matching row) don't participate in avg() - either for the numerator or denominator, if you want residences without any meterings to count when calcukating the average (as if they have a single zero metering for the purposes of dividing the total value), use this query:
select
number_residents,
count(distinct r.id) residences_count,
sum(value) / count(r.id) average_value
from Res r
left join Metering m on m.id = r.id
group by number_residents
Because res.id is never null, count(r.id) counts the number of meterings plus 1 for every residence without any meterings.
SELECT o.Date1, o.Date2
FROM customers AS c, products AS p, products_ids AS pi, orders AS o, temptable AS te
WHERE p.productid = pi.productidD
AND pi.prodno = te.prodno
AND c.custid = o.custid
AND o.custid = te.custid
AND te.custid = '24'
GROUP BY pi.productiD
The result of the query returns each time the same date(of one row) to all the rows,even if the dates are different inside mysql.
As has been mentioned it is worth switching to the newer ANSI 92 JOIN syntax for clarity, this can avoid accidental cross joins, so your query would become:
SELECT o.Date1, o.Date2
FROM customers AS c
INNER JOIN orders AS o
ON c.custid = o.custid
INNER JOIN temptable AS te
o.custid = te.custid
INNER JOIN products AS p
ON pi.prodno = te.prodno
INNER JOIN products_ids AS pi
ON p.productid = pi.productidD
WHERE te.custid = '24'
GROUP BY pi.productiD;
However, this is not the problem in your query, the problem is the fact that you are abusing the functionality within MySql whereby you can select items that are not part of the group by:
Here you are telling the query to select 1 row per distinct value for pi.ProductID, there could be multiple different values for o.Date1 and o.Date2 for each pi.ProductID, and you are giving the query no hints as to which of these multiple possibilities to choose from.
Using columns in the select that are not in the group by is permitted by ANSI standards but only when the columns in the select are functionally dependant on columns within the group by, this is very hard to adhere to so most DBMS simply do not allow columns in the select that are not in the group by.
To demonstrate consider this dataset (T)
OrderID ProductID Date1 Date2
1 1 20130401 20130402
2 1 20130402 20130403
3 2 20130403 20130404
4 2 20130404 20130405
5 2 20130405 20130406
If (as in your case) you did:
SELECT OrderID, ProductID, Date1, Date2
FROM T
GROUP BY ProductID
You would probably get:
OrderID ProductID Date1 Date2
1 1 20130401 20130402
3 2 20130403 20130404
Just taking the first row for each product ID, however since the query is non deterministic it would be equally correct for the query to return the last row for each productID:
OrderID ProductID Date1 Date2
2 1 20130402 20130403
5 2 20130405 20130406
It is a common myth that adding order by will help this, e.g.
SELECT OrderID, ProductID, Date1, Date2
FROM T
GROUP BY ProductID
ORDER BY OrderID;
MySql determines the rows to be returned before applying the order by, so even adding ORDER BY OrderID does not guarantee the first order for each productID is returned.
The MySQL Docs state
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause.
Finally to elaborate on what I said about functionally dependant columns, because in this dataset OrderID is a primary key, according to ANSI standards you could write:
SELECT OrderID, ProductID, Date1, Date2
FROM T
GROUP BY OrderID;
So, while I have not really answered your question I hopefully have shown where you are going wrong. You really need to establish what you are trying to achieve by the group by, and if you still haven't got a solution then i'd suggest a new, more constructive question, with sample data and an expected output with clear rules as to why the expexted output is expexted.