How to make this query for this scenario in SQL SERVER? - sql

I have two table called TransactionItem, ItemRelation, below are my queries
select sum(dqty) as QUANTITY FROM [HQMatajer].[dbo].[TransactionItem]
where ItemLookupCode='306519P0001' group by Tyear, Tmonth
select
ItemLookupCode, convert(INT,SUBSTRING(ItemLookupCode,8,4)) as SIZE from
[HQMatajer].[dbo].[ItemRelation] where ItemLookupCode='319348P0001' or
ChildItemLookupCode1='319348P0001' or ChildItemLookupCode2='319348P0001' or
ChildItemLookupCode='319348P0001'
calculations
Result of my query of two tables
As you can see the result on image, now I just want to divide all the values of quantity from first result by size from second result. For example
QUANTITY
6/48
64/48
167/48
31/48
2367/48
1664/48
8/48
How to do it in a single query?.

How about this:
SELECT QUANTITY / SIZE QUANTITY FROM (
select sum(dqty) as QUANTITY
FROM [HQMatajer].[dbo].[TransactionItem]
where ItemLookupCode='306519P0001'
group by Tyear, Tmonth
) A
CROSS JOIN (
select ItemLookupCode, convert(INT,SUBSTRING(ItemLookupCode,8,4)) as SIZE
from [HQMatajer].[dbo].[ItemRelation]
where
ItemLookupCode='319348P0001'
or ChildItemLookupCode1='319348P0001'
or ChildItemLookupCode2='319348P0001'
or ChildItemLookupCode='319348P0001'
) B

You can calculate size and put it in a variable. Then you can use the same variable for division in the second query.
declare #size int;
set #size= (Select top 1 convert(INT,SUBSTRING(ItemLookupCode,8,4)) as SIZE from [HQMatajer].[dbo].[ItemRelation]
where ItemLookupCode='319348P0001' or ChildItemLookupCode1='319348P0001' or ChildItemLookupCode2='319348P0001' or ChildItemLookupCode='319348P0001')
select sum(dqty)/#size as QUANTITY FROM [HQMatajer].[dbo].[TransactionItem]
where ItemLookupCode='306519P0001'
group by Tyear, Tmonth

CREATE TABLE #Tbl1(Qty INT)
CREATE TABLE #Tbl2(Size INT)
INSERT INTO #Tbl1(Qty)
SELECT 6 UNION ALL
SELECT 64 UNION ALL
SELECT 167
INSERT INTO #Tbl2(Size)
SELECT 48
SELECT Qty / (SELECT Size FROM #Tbl2)
FROM #Tbl1

Use the variable to store the sum. then we can use this variable while dividing in the next query.
Declare #QUANTITY float;
select #QUANTITY=sum(dqty)
FROM [HQMatajer].[dbo].[TransactionItem]
where ItemLookupCode='306519P0001'
group by Tyear, Tmonth
select ItemLookupCode
,convert(INT,SUBSTRING(ItemLookupCode,8,4)) as SIZE, convert(INT,SUBSTRING(ItemLookupCode,8,4))/#QUANTITY
from [HQMatajer].[dbo].[ItemRelation]
where (ItemLookupCode='319348P0001' or ChildItemLookupCode1='319348P0001' or ChildItemLookupCode2='319348P0001' or ChildItemLookupCode='319348P0001')

Related

SUM AND GROUP OUTPUT BY DAY SQL

I can not reference by the aliases Gross_Demand and Units.
,(CASE WHEN CONCAT(',',post_event_list,',') LIKE '%,1,%' THEN SPLIT(item, ";")[safe_offset(3)] END) Gross_Demand
,(CASE WHEN CONCAT(',',post_event_list,',') LIKE '%,1,%' THEN SPLIT(item, ";")[safe_offset(2)] END) Units
Intentionally not giving you a specific answer, but I would structure your query like this:
-- Declare your variables
DECLARE StartDate...
with hits as (
-- select what you need from your hits table, filter and unnest here
),
products as (
-- select and filter what you need from your products table here
),
joined as (
-- join the two sources together and do any additional filtering
select
date, visits, orders, gross_demand, units, etc...
from hits
join products
),
calcs as (
select
*,
gross_demand*units as revenue,
orders/visits * 100 as conversion_pct,
gross_demand*units/visits as revenue_per_visit
from joined
)
select * from calcs
Breaking down your logic into steps/chunks often makes things way easier.

Finding the Difference of Two Results

I have two results with two different dates (a recent one and the previous one) the numbers below are the result 250 being the most recent and 300 being the previous result:
250
300
The code I use is here:
SELECT TOP 2
MY FIELD as bmi
FROM
MY TABLE
ORDER BY
THE DATE FIELD DESC
Within this same code I want to be able to find the difference between those two numbers and for that to appear not the two numbers?
I have tried a few things of skipping N rows etc but now I don't know what I can do?
I think you want something like this:
declare #firstBmiRes int
declare #secondBmiRes int
SET #firstBmiRes = 250 /* insert your query */
SET #secondBmiRes = 300 /* insert your query */
(SELECT SUM(#secondBmiRes - #firstBmiRes))
If you want to continue to use the calculated result. You can obviously store the value into another variable like this:
declare #bmi int
SET #bmi = (SELECT SUM(#secondBmiRes - #firstBmiRes))
SELECT #bmi
2nd Approach:
Since we don't have very much information to work with. you could try something like this... But i'm assuming a lot of your datastructure here.
declare #BmiScore int
declare #firstBmiRes int
declare #secondBmiRes int
SET #firstBmiRes = (SELECT TOP 1 MY_FIELD
FROM MY_TABLE
ORDER BY DATE_FIELD DESC)
SET #secondBmiRes = (SELECT MY_FIELD
FROM MY_TABLE
ORDER BY DATE_FIELD DESC
OFFSET 1 ROW
FETCH NEXT 1 ROW ONLY)
SET #bmiScore = (SELECT SUM(#secondBmiRes - #firstBmiRes))
SELECT #bmiScore
SELECT
MYFIELD - LAG (MYFIELD,1) OVER (ORDER BY MYDATE) AS BMI
FROM
MYTABLE;
ORDER BY MYDATE DESC
Using a LEAD function if you want your code to be a part of new code for some reason:
select TOP 1 (bmi - lead(bmi) over (order by date_field)) as result
from( SELECT TOP 2 my_field as bmi
, date_field
FROM my_table
ORDER BY date_field DESC) A
Here is a DEMO
Or by LAG :
select TOP 1 (lag(my_field) over (order by date_field) - my_field ) as result
FROM my_table
ORDER BY date_field DESC;
You can use LEAD/ LAG if your version of SQL Server supports these functions. If you are on an older version then you can use a windowed function to apply an order to the rows.
Here's your data going into a temporary table variable:
DECLARE #MY_TABLE TABLE (THE_DATE_FIELD DATE, MY_FIELD INT);
INSERT INTO #MY_TABLE SELECT '20200114', 300 UNION ALL SELECT '20200113', 250;
...and here's a query to perform the calculation you needed:
WITH x AS (
SELECT TOP 2
THE_DATE_FIELD,
MY_FIELD AS bmi,
ROW_NUMBER() OVER (ORDER BY THE_DATE_FIELD DESC) AS order_id
FROM
#MY_TABLE)
SELECT
MAX(CASE WHEN order_id = 1 THEN bmi END) - MAX(CASE WHEN order_id = 2 THEN bmi END) AS difference_bmi
FROM
x;
If I peek at the data from the CTE then I see this (and this is why I included the date field, which is redundant, and could otherwise be removed):
THE_DATE_FIELD bmi order_id
2020-01-14 300 1
2020-01-13 250 2
Now it's simply a case of picking the two values, as one has an order_id = 1 and one has an order_id = 2.

how to perform multiple aggregations on a single SQL query

I have a table with Three columns:
GEOID, ParcelID, and PurchaseDate.
The PKs are GEOID and ParcelID which is formatted as such:
GEOID PARCELID PURCHASEDATE
12345 AB123 1/2/1932
12345 sfw123 2/5/2012
12345 fdf323 4/2/2015
12346 dfefej 2/31/2022 <-New GEOID
What I need is an aggregation based on GEOID.
I need to count the number of ParcelIDs from last month PER GEOID
and I need to provide a percentage of that GEOID of all total sold last month.
I need to produce three columns:
GEOID Nbr_Parcels_Sold Percent_of_total
For each GEOID, I need to know how many Parcels Sold Last month, and with that Number, find out how much percentage that entails for all Solds.
For example: if there was 20 Parcels Sold last month, and 4 of them were sold from GEOID 12345, then the output would be:
GEOID Nbr_Parcels_Sold Perc_Total
12345 4 .2 (or 20%)
I am having issues with the dual aggregation. The concern is that the table in question has over 8 million records.
if there is a SQL Warrior out here who have seen this issue before, Any wisdom would be greatly appreciated.
Thanks.
Hopefully you are using SQL Server 2005 or later version, in which case you can get advantage of windowed aggregation. In this case, windowed aggregation will allow you to get the total sale count alongside counts per GEOID and use the total in calculations. Basically, the following query returns just the counts:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Total_Parcels_Sold = SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The COUNT(*) call gives you counts per GEOID, according to the GROUP BY clause. Now, the SUM(...) OVER expression gives you the grand total count in the same row as the detail count. It is the empty OVER clause that tells the SUM function to add up the results of COUNT(*) across the entire result set. You can use that result in calculations just like the result of any other function (or any expression in general).
The above query simply returns the total value. As you actually want not the value itself but a percentage from it for each GEOID, you can just put the SUM(...) OVER call into an expression:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Percent_of_total = COUNT(*) * 100 / SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The above will give you integer percentages (truncated). If you want more precision or a different representation, remember to cast either the divisor or the dividend (optionally both) to a non-integer numeric type, since SQL Server always performs integral division when both operands are integers.
How about using sub-query to count the sum
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
EDIT
To update another table by the result, use UPDATE under WITH()
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
UPDATE target SET
Nbr_Parcels_Sold = source.Nbr_Parcels_Sold,
Perc_Total = source.Perc_Total
FROM
[AnotherTable] target
INNER JOIN
(
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
) source ON target.GEOID = source.GEOID
Try the following. It grabs the total sales into a variable then uses it in the subsequent query:
DECLARE #pMonthStartDate DATETIME
DECLARE #MonthEndDate DATETIME
DECLARE #TotalPurchaseCount INT
SET #pMonthStartDate = <EnterFirstDayOfAMonth>
SET #MonthEndDate = DATEADD(MONTH, 1, #pMonthStartDate)
SELECT
#TotalPurchaseCount = COUNT(*)
FROM
GEOIDs
WHERE
PurchaseDate BETWEEN #pMonthStartDate
AND #MonthEndDate
SELECT
GEOID,
COUNT(PARCELID) AS Nbr_Parcels_Sold,
CAST(COUNT(PARCELID) AS FLOAT) / CAST(#TotalPurchaseCount AS FLOAT) * 100.0 AS Perc_Total
FROM
GEOIDs
WHERE
ModifiedDate BETWEEN #pMonthStartDate
AND #MonthEndDate
GROUP BY
GEOID
I'm guessing your table name is GEOIDs. Change the value of #pMonthStartDate to suit yourself. If your PKs are as you say then this will be a quick query.

Only one expression can be specified in the select list. in sql query

this query works fine for me.
SELECT (SUM(AveragePrice)/COUNT(1)) AS AveragePrice, SUM(ItemsSold) AS ItemSold ,(SUM(AveragePrice * ItemsSold)) AS TotalSale FROM dbo.tbl_ProductSales
WHERE ProductID IN ( SELECT ProductID FROM tbl_ProductPostions WHERE tbl_ProductPostions.SearchID=3 AND SaleDate='2012-02-02 00:00:00.000')
GROUP BY SaleDate
and resuts like this
AveragePrice | ItemSold | TotalSale
10 | 2 | 2000
but when i embed this query like this
SELECT * ,(SELECT (SUM(AveragePrice)/COUNT(1)) AS AveragePrice, SUM(ItemsSold) AS ItemSold ,(SUM(AveragePrice * ItemsSold)) AS TotalSale FROM dbo.tbl_ProductSales
WHERE ProductID IN ( SELECT ProductID FROM tbl_ProductPostions WHERE tbl_ProductPostions.SearchID=tbl_SearchParameters.SearchID AND SaleDate='2012-02-02 00:00:00.000')
GROUP BY SaleDate )
FROM tbl_SearchParameters
i got an error like this.
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
i know i am crossing the limits but is there any alternate way to do this.
i know the function can be created to do this task. but is essential to create
three function separately to compute this these aggregate Average Price,Item Sold,Total Sale?
while i am sure a single query can compute three aggregate for me ?
can any body suggest me proper solution ? i just want to get ride of creating three functions separately for these aggregate respectively.
Regards.
You can use APPLY() operator
SELECT *
FROM tbl_SearchParameters p
CROSS APPLY (
SELECT SUM(AveragePrice/COUNT(1)) AS AveragePrice,
SUM(ItemsSold) AS ItemSold,
SUM(AveragePrice * ItemsSold) AS TotalSale
FROM dbo.tbl_ProductSales
WHERE ProductID IN (SELECT ProductID
FROM tbl_ProductPostions
WHERE tbl_ProductPostions.SearchID = p.SearchID
AND SaleDate='2012-02-02 00:00:00.000')
GROUP BY SaleDate
) o
Try to remove the second SELECT like:
SELECT * ,(SUM(AveragePrice)/COUNT(1)) AS AveragePrice,
SUM(ItemsSold) AS ItemSold ,
(SUM(AveragePrice * ItemsSold)) AS TotalSale
FROM dbo.tbl_ProductSales
WHERE ProductID IN (SELECT ProductID
FROM tbl_ProductPostions
WHERE tbl_ProductPostions.SearchID=tbl_SearchParameters.SearchID
AND SaleDate='2012-02-02 00:00:00.000')
GROUP BY SaleDate )
FROM tbl_SearchParameters

SQL query ...multiple max value selection. Help needed

Business World 1256987 monthly 10 2009-10-28
Business World 1256987 monthly 10 2009-09-23
Business World 1256987 monthly 10 2009-08-18
Linux 4 U 456734 monthly 25 2009-12-24
Linux 4 U 456734 monthly 25 2009-11-11
Linux 4 U 456734 monthly 25 2009-10-28
I get this result with the query:
SELECT DISTINCT ljm.journelname,ljm. subscription_id,
ljm.frequency,ljm.publisher, ljm.price, ljd.receipt_date
FROM lib_journals_master ljm,
lib_subscriptionhistory
lsh,lib_journal_details ljd
WHERE ljd.journal_id=ljm.id
ORDER BY ljm.publisher
What I need is the latest date in each journal?
I tried this query:
SELECT DISTINCT ljm.journelname, ljm.subscription_id,
ljm.frequency, ljm.publisher, ljm.price,ljd.receipt_date
FROM lib_journals_master ljm,
lib_subscriptionhistory lsh,
lib_journal_details ljd
WHERE ljd.journal_id=ljm.id
AND ljd.receipt_date = (
SELECT max(ljd.receipt_date)
from lib_journal_details ljd)
But it gives me the maximum from the entire column. My needed result will have two dates (maximum of each magazine), but this query gives me only one?
You could change the WHERE statement to look up the last date for each journal:
AND ljd.receipt_date = (
SELECT max(subljd.receipt_date)
from lib_journal_details subljd
where subljd.journelname = ljd.journelname)
Make sure to give the table in the subquery a different alias from the table in the main query.
You should use Group By if you need the Max from date.
Should look something like this:
SELECT
ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
, **MAX(ljd.receipt_date)**
FROM
lib_journals_master ljm
, lib_subscriptionhistory lsh
, lib_journal_details ljd
WHERE
ljd.journal_id=ljm.id
GROUP BY
ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
Something like this should work for you.
SELECT ljm.journelname
, ljm.subscription_id
, ljm.frequency
, ljm.publisher
, ljm.price
,md.max_receipt_date
FROM lib_journals_master ljm
, ( SELECT journal_id
, max(receipt_date) as max_receipt_date
FROM lib_journal_details
GROUP BY journal_id) md
WHERE ljm.id = md.journal_id
/
Note that I have removed the tables from the FROM clause which don't contribute anything to the query. You may need to replace them if yopu simplified your scenario for our benefit.
Separate this into two queries one will get journal name and latest date
declare table #table (journalName as varchar,saleDate as datetime)
insert into #table
select journalName,max(saleDate) from JournalTable group by journalName
select all fields you need from your table and join #table with them. join on journalName.
Sounds like top of group. You can use a CTE in SQL Server:
;WITH journeldata AS
(
SELECT
ljm.journelname
,ljm.subscription_id
,ljm.frequency
,ljm.publisher
,ljm.price
,ljd.receipt_date
,ROW_NUMBER() OVER (PARTITION BY ljm.journelname ORDER BY ljd.receipt_date DESC) AS RowNumber
FROM
lib_journals_master ljm
,lib_subscriptionhistory lsh
,lib_journal_details ljd
WHERE
ljd.journal_id=ljm.id
AND ljm.subscription_id = ljm.subscription_id
)
SELECT
journelname
,subscription_id
,frequency
,publisher
,price
,receipt_date
FROM journeldata
WHERE RowNumber = 1