I'm trying to write an SQL query to return information including product code, yearly sales revenues, costs, sales people information from two different tables. I need to return the product ID information for the product with the lowest'onboarding cost' for the 'north' region.
I have used WHERE Region = 'North' to just get the product info for the North region, and ORDER BY onboarding cost; to sort this low to high and find the product with the lowest cost. Is there a way of just returning the product with the lowest onboarding cost for the north region?
In the WHERE clause you could add:
... AND onboarding cost=(SELECT MAX(onboarding cost) FROM ... WHERE region='North' ...)
SELECT
ProductRevenueAndCosts.ProductID,
ProductRevenueAndCosts.SalesRevenueYear1,
ProductRevenueAndCosts.SalesRevenueYear2,
ProductRevenueAndCosts.OperationalCostsYear1,
ProductRevenueAndCosts.OperationalCostsYear2,
ProductRevenueAndCosts.OnboardingCost,
SalesPeople.FirstName,
SalesPeople.LastName,
SalesPeople.Region
FROM SalesPeople INNER JOIN ProductRevenueAndCosts ON
SalesPeople.SalesPersonID = ProductRevenueAndCosts.SalesPersonID
WHERE SalesPeople.Region = "North"
AND ProductRevenueAndCosts.OnboardingCost=(
SELECT MAX(ProductRevenueAndCosts.OnboardingCost)
FROM SalesPeople INNER JOIN ProductRevenueAndCosts ON
SalesPeople.SalesPersonID = ProductRevenueAndCosts.SalesPersonID
WHERE SalesPeople.Region = "North"
)
ORDER BY ProductRevenueAndCosts.Onboardingcost DESC -- this is obsolete
;
But this will eventually return more than one result - in case that more than one product has the same highest onboaring cost.
Yes, you need to limit the number of records, like this:
MySQL, PostgreSQL
SELECT
ProductRevenueAndCosts.ProductID,
ProductRevenueAndCosts.SalesRevenueYear1,
ProductRevenueAndCosts.SalesRevenueYear2,
ProductRevenueAndCosts.OperationalCostsYear1,
ProductRevenueAndCosts.OperationalCostsYear2,
ProductRevenueAndCosts.OnboardingCost,
SalesPeople.FirstName,
SalesPeople.LastName,
SalesPeople.Region
FROM SalesPeople INNER JOIN ProductRevenueAndCosts ON
SalesPeople.SalesPersonID = ProductRevenueAndCosts.SalesPersonID
WHERE SalesPeople.Region = "North"
ORDER BY ProductRevenueAndCosts.Onboardingcost DESC
LIMIT 0, 1;
Where 0 is the starting index (first row) and 1 is the number of records you want to get.
SQL Server
SELECT TOP 1
ProductRevenueAndCosts.ProductID,
ProductRevenueAndCosts.SalesRevenueYear1,
ProductRevenueAndCosts.SalesRevenueYear2,
ProductRevenueAndCosts.OperationalCostsYear1,
ProductRevenueAndCosts.OperationalCostsYear2,
ProductRevenueAndCosts.OnboardingCost,
SalesPeople.FirstName,
SalesPeople.LastName,
SalesPeople.Region
FROM SalesPeople INNER JOIN ProductRevenueAndCosts ON
SalesPeople.SalesPersonID = ProductRevenueAndCosts.SalesPersonID
WHERE SalesPeople.Region = "North"
ORDER BY ProductRevenueAndCosts.Onboardingcost DESC;
Where TOP 1 tells the RDBMS that you are interested only in the very first row.
Oracle
SELECT
ProductRevenueAndCosts.ProductID,
ProductRevenueAndCosts.SalesRevenueYear1,
ProductRevenueAndCosts.SalesRevenueYear2,
ProductRevenueAndCosts.OperationalCostsYear1,
ProductRevenueAndCosts.OperationalCostsYear2,
ProductRevenueAndCosts.OnboardingCost,
SalesPeople.FirstName,
SalesPeople.LastName,
SalesPeople.Region
FROM SalesPeople INNER JOIN ProductRevenueAndCosts ON
SalesPeople.SalesPersonID = ProductRevenueAndCosts.SalesPersonID
WHERE SalesPeople.Region = "North"
ORDER BY ProductRevenueAndCosts.Onboardingcost DESC
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY;
Related
So I have 2 SQL queries both including the same variable: basically (n_orders and orders_count) should return the same exact results. Problem is:
the 2 columns are not always equivalent for all values
the count of different values changes every run
so first run could be that 20 rows have different (n_orders, orders_count) values then 2nd run says count of different values is 56 for example and so on with changing counts every run.
Query 1:
SELECT product_id,
packing_unit_id,
count(DISTINCT product_sales_order.sales_order_id)
FROM product_sales_order
WHERE product_sales_order.created_at::date BETWEEN '{start}' AND '{end}'
GROUP BY 1, 2
ORDER BY product_id, packing_unit_id
Query 2:
select kpis.*, lr.lr
FROM
(SELECT product_sales_order.product_id,
product_sales_order.packing_unit_id,
count(DISTINCT product_sales_order.sales_order_id) AS orders_count,
count(DISTINCT sales_orders.retailer_id) AS retailers_count,
count(DISTINCT product_sales_order.sales_order_id)*1.0 / count(DISTINCT sales_orders.retailer_id) AS frequency,
(count(DISTINCT sales_orders.retailer_id)*1.0 /(SELECT count(DISTINCT sales_orders.retailer_id) AS month_retailers
FROM sales_orders
JOIN retailers on retailers.id = sales_orders.retailer_id
WHERE sales_orders.created_at::Date BETWEEN '{start}' AND '{end}'
AND sales_orders.sales_order_status_id = 6
AND retailers.is_market_type_private = false)) AS reach,
sum(product_sales_order.total_price) AS nmv,
(sum(product_sales_order.total_price)*1.0 / (SELECT sum(product_sales_order.total_price) AS month_nmv
FROM product_sales_order
WHERE product_sales_order.created_at::Date BETWEEN '{start}' AND '{end}'
AND product_sales_order.purchased_item_count <> 0)) AS contribution,
sum(product_sales_order.purchased_item_count * product_sales_order.basic_unit_count) AS bskt_size,
sum(product_sales_order.total_price)*1.0 / count(DISTINCT product_sales_order.sales_order_id) AS avg_ts,
sum(product_sales_order.total_price)*1.0 / count(DISTINCT sales_orders.retailer_id) AS nmv_p_retailer
FROM product_sales_order
LEFT JOIN sales_orders ON sales_orders.id = product_sales_order.sales_order_id
LEFT JOIN products ON products.id = product_sales_order.product_id
LEFT JOIN retailers on retailers.id = sales_orders.retailer_id
WHERE product_sales_order.created_at::date BETWEEN '{start}' AND '{end}'
GROUP BY 1,2
ORDER BY product_sales_order.product_id, product_sales_order.packing_unit_id, orders_count
) as kpis
LEFT JOIN (
SELECT performance.lost_revenue.product_id,
sum(performance.lost_revenue.lost_revenue) as lr
FROM performance.lost_revenue
WHERE performance.lost_revenue.created_at::Date between '{start}' AND '{end}'
GROUP BY 1
)as lr on lr.product_id = kpis.product_id
What could be corrected regarding the structure of the 2nd SQL query to make it yield the same results for orders_count?
Why does different values count return different results every run?
The three tables that I'm linking are item_scan_fact, member_dimension and store_dimension. So far this is what I have:
SELECT
store_dimension.store_number,
member_dimension.member_number
COUNT (item_scan_fact.visit_number) AS NumVisits
FROM
member_dimension,
item_scan_fact
INNER JOIN store_dimension
ON item_scan_fact.member_key = member_dimension.member_key
AND item_scan_fact.store_key = store_dimension.store_key
GROUP BY
store_dimension.store_number,
member_dimension.member_number, NumVisits;
On the surface it appears solvable with a couple Common Table Expressions
Does this help point you in the right direction?
WITH s1 -- JJAUSSI: Find the visit_number_count by member_key and store_key
AS
(SELECT isf.member_key
,isf.store_key
-- JJAUSSI: DISTINCT resolves a potential 1:N (one to many) relationship here
,COUNT( DISTINCT isf.visit_number) AS visit_number_count
FROM item_scan_fact isf
GROUP BY isf.member_key
,isf.store_key),
s2 -- JJAUSSI: Find the visit_number_count_max by member_key
AS
(SELECT s1.member_key
,MAX(s1.visit_number_count) AS visit_number_count_max
FROM s1
GROUP BY s1.member_key)
-- JJAUSSI: Use this version to see the list of store_key values
-- that have the visit_number_count_max value. This has the potential
-- to be a 1:N relationship.
SELECT s1.member_key
,md.member_number
,s1.store_key
,sd.store_number
,s1.visit_number_count
FROM s2 INNER JOIN s1
ON s2.member_key = s1.member_key
AND s2.visit_number_count_max = s1.visit_number_count
INNER JOIN store_dimension sd
ON sd.store_key = s1.store_key
INNER JOIN member_dimension md
ON md.member_key = s1.member_key;
If this is what you were going for...congratulations! On to the next query!
If you ultimately are after a single store_key response for each member_key (basically you want to determine the member_key's "primary" store_key) then an additional step is probably needed (depending on your data).
Here are some ideas:
Evaluate the member_key based on some other summable facet of
item_scan_fact (like total price paid?)
If you consider all store_key values of equal merit that have the same visit_number_count_max value for a given member_key, just choose a store_key with MAX or MIN
You would seem to want:
SELECT member_number, MAX(NumVisits)
FROM (SELECT sd.store_number, md.member_number
COUNT(*) AS NumVisits
FROM member_dimension md JOIN
item_scan_fact isf
ON md.member_key = isf.member_key JOIN
store_dimension sd
ON isf.store_key = sd. store_key
GROUP BY sd.store_number, md.member_number
) sm
GROUP BY member_number;
If you want to return both the max and the matching customer number you can apply a Teradata SQL extension, qualify:
SELECT sd.store_number, md.member_number
COUNT(*) AS NumVisits
FROM member_dimension md JOIN
item_scan_fact isf
ON md.member_key = isf.member_key JOIN
store_dimension sd
ON isf.store_key = sd. store_key
GROUP BY sd.store_number, md.member_number
QUALIFY
rank() -- might return multiple rows with the same max, ROW_NUMBER a single row
over (partition by sd.store_number
order by NumVisits desc) = 1
I need to pull back a set of data for a view where only rows with the the minimum cost are returned. I am joining 3 tables and they are big tables (225 million records a piece give or take) so performance is essential.
SELECT RIC.CarrierName, L.LoadGuid, RIC.RateIQCarrierid, RIRD.Cost
FROM tblLoads L
INNER JOIN RateIQRecord RIR ON L.LoadGuid = RIR.LoadGuId
INNER JOIN RateIQCarrier RIC ON RIR.RateIQRecordID = RIC.RateIQRecordID
INNER JOIN RateIQRateDetail RIRD ON RIC.RateIQRecordID = RIRD.RateIQRecordID
AND CAST(L.CreatedDate AS Datetime) Between '03/3/2014' and '03/3/2014 23:59:59.997'
Here is an example of the data set based of the code above
CarrierName LoadGuid Carrierid Cost
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677951 192.51
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677921 153.17
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677925 196.28
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677947 280.65
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677949 241.71
Here is what I need:
CarrierName LoadGuid Carrierid Cost
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677921 153.17
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677925 196.28
Try this out:
Note:I'm assuming you have SQL Server 2008 or above. ROW_NUMBER() won;t work otherwise.
SELECT *
FROM
(
SELECT RIC.CarrierName,
L.LoadGuid,
RIC.RateIQCarrierid,
RIRD.Cost,
--Partition says look at each carrier as a group, then number them in order of cost lowest to highest.
ROW_NUMBER() OVER (PARTITION BY RIC.CarrierName ORDER BY Cost) rank_num
FROM tblLoads L
INNER JOIN RateIQRecord RIR
ON L.LoadGuid = RIR.LoadGuId
INNER JOIN RateIQCarrier RIC
ON RIR.RateIQRecordID = RIC.RateIQRecordID
INNER JOIN RateIQRateDetail RIRD
ON RIC.RateIQRecordID = RIRD.RateIQRecordID
--Don't do it this way
--AND CAST(L.CreatedDate AS Datetime) Between '03/3/2014' and '03/3/2014 23:59:59.997'
--Try this instead
AND CAST(L.CreatedDate AS DATE) = '03/03/2014'
) A
--Only grab the lowest number aka first of row number
WHERE A.rank_num = 1
I am finding it difficult to modify an existing SQL query to group records on two columns. Following is the query which retrieves records from multiple tables by joining:
SELECT
InM.invm_No AS DocNo,
InM.docs_DocCode,
D.doctyp_Desc AS DocType,
L.loc_Desc AS Site,
InM.sup_Code AS Supplier,
InD.invd_Qty,
InD.invd_Rate
FROM
[SI_InventoryMaster] InM
INNER JOIN
[SI_DocType] AS D ON InM.doctyp_Code = D.doctyp_Code
INNER JOIN
SI_Supplier S ON InM.sup_Code = S.sup_Code
INNER JOIN
[SI_InventoryDetail] AS InD ON InD.invm_No = InM.invm_No
AND InM.invm_verified = 1
AND InM.docs_DocCode = 'GRN'
AND MONTH (InM.invm_Date) = 12
AND YEAR(InM.invm_date) = 2013
INNER JOIN
SI_Location L ON InD.loc_code = L.loc_Code
ORDER BY
InM.invm_No
Which results the following:
I need to group records "by DocNo by Site" and find total amount for each site. Total amount will be last column in this resultset and it is net of product of InD.invd_Qty and InD.invd_Rate for each site.
For DocNo: 00000030, there are 4 records of CWS Store Site, so its total amount would be calculated as: 7684.999+7684.999+3000+3000=21369.998
In this particular example, modified query should return following resultset:
Please help.
Thanks.
Try grouping on all the columns associated with those two columns. Something like:
SELECT InM.invm_No AS DocNo, InM.docs_DocCode, D.doctyp_Desc AS DocType,
L.loc_Desc AS Site, InM.sup_Code AS Supplier,
sum(InD.invd_Qty),
sum(InD.invd_Rate)
FROM [SI_InventoryMaster] InM INNER JOIN
[SI_DocType] AS D
ON InM.doctyp_Code = D.doctyp_Code INNER JOIN
SI_Supplier S
ON InM.sup_Code = S.sup_Code INNER JOIN
[SI_InventoryDetail] AS InD
ON InD.invm_No = InM.invm_No AND
InM.invm_verified = 1 AND
InM.docs_DocCode = 'GRN' AND
MONTH (InM.invm_Date) = 12 AND
YEAR(InM.invm_date) = 2013 INNER JOIN
SI_Location L
ON InD.loc_code = L.loc_Code
GROUP BY InM.invm_No AS DocNo, InM.docs_DocCode, D.doctyp_Desc AS DocType,
L.loc_Desc AS Site, InM.sup_Code AS Supplier;
I have 3 tables Campaign, Mall, MallCampaign (many-to-many) and want to order nearest campaigns which are available in one or more malls.
In the first query; I am eligible for reaching the campaigns' distance which are available in different malls. But need to do it for all campaigns not only one (Id=79). I couldn't manage to do it with JOIN.
SELECT
m.MallId,
ROUND(#geo1.STDistance(geography::Point(m.MallLatitude, m.MallLongitude, 4326))/1000,1) AS Distance
FROM
MallCampaign mc
INNER JOIN
Mall m ON m.MallId = mc.MallId
WHERE
m.IsActive != 0 AND mc.CampaignId = 79
ORDER BY
Distance
SELECT
ca.CampaignId, ca.CampaignTitle
FROM
Campaign ca
Does this do what you want? It sorts by campaign id first and then by distance:
SELECT mc.CampaignId, m.MallId,
ROUND(#geo1.STDistance(geography::Point(m.MallLatitude, m.MallLongitude, 4326))/1000,1) AS Distance
FROM MallCampaign mc join
Mall m
ON m.MallId = mc.MallId
WHERE m.IsActive <> 0
ORDER BY mc.CampaignId, Distance;
EDIT:
Your original question didn't have a top in it, which I sort of expected. To handle this, you want to use row_number(). In this case, it is easiest to do two subqueries (or CTEs):
select CampaignId, MallId, Distance
from (select mc.*,
row_number() over (partition by CampaignId order by distance) as seqnum
from (SELECT mc.CampaignId, m.MallId,
ROUND(#geo1.STDistance(geography::Point(m.MallLatitude, m.MallLongitude, 4326))/1000,1) AS Distance
FROM MallCampaign mc join
Mall m
ON m.MallId = mc.MallId
WHERE m.IsActive <> 0
) mc
) mc
where seqnum = 1;