SQL Server Distinct on ID - sql-server

I'm encountering a problem, when trying to get the right result.
Working on a SQL server.
I want to know how many 'products' of a certain type of material have been made on each day for a period of 6 months.
The problem I'm encountering is the fact that the same product_id can be stored multiple times in the table. However I want those to count as 1. Also I have no clue how to show the count and the date together for multiple days. I've been looking around but I can't seem to find the right page, if there is one, a link to that page is greatly appreciated.
The columns I'm working with are
| Product_id | Creation_date | Material |
Query:
SELECT
COUNT(DISTINCT PRODUCT_ID) AS total products,
creation_date
FROM
DB
WHERE
MATERIAL = 'dummy'
AND CREATION_DATE BETWEEN '2022-02-02 00:01:23.763' AND '2022-02-02 23:55:23.763'
This is the result I want:
Total products
DATE
the count
2022-02-01
the count
2022-02-02
the count
2022-02-03
for a period of 6 months.
Thanks in advance.

Please try this,
SELECT COUNT(DISTINCT PRODUCT_ID) as total products
, creation_date
FROM DB
WHERE MATERIAL = 'dummy' AND CREATION_DATE BETWEEN /startdate/ AND
/enddate/
group by creation_date
If this doesn't help, please provide some sample data and expected output

Related

Creating Attendance Report with SSRS

I am trying to create a Attendance result set in SQL Server for using it in a SSRS report. The Employee Attendance table is as below:
EmpId
ADate
In
Out
1
2023-01-01
8:00
15:00
I need to calculate the Total working days for all months in a year and display the number of working days per employee. Report format should be as follows:
Saturday and Sunday being weekend, I can able to get the no of working days monthly.
Another table tbl_Holiday has entries for holidays Fromdate and ToDate. I need to consider that also when calculating working days. Several number of results i got from the internet for calculating this. But when creating a view using this data , it has to calculate workdays for each employee row
SELECT
EmpName, EmpId,
(SELECT COUNT(*) FROM tbl_EmpAttendance
WHERE EmpRecId = A.RecId
GROUP BY MONTH(Adate), YEAR(Adate)) AS WorkedDays,
dbo.fn_GetWorkDays(DATEFROMPARTS(YEAR(ADate), MONTH(ADate), 1), EOMONTH(ADate)) AS workingDays
FROM
tbl_Employee A
LEFT JOIN
tbl_EmpAttendance B ON A.RecId = B.EmpRecId
fn_GetWorkDays - calculates the working days for month.
I need to get number of holidays from tbl_holiday too, I understand that this query is becoming more complex than I thought. There must be simpler way to achieve this, can anyone please help?
I tried to get the result in one single view, for using that as SSRS report dataset

WHERE clause returning mixed results + Grouping weekly data by quarter

I've got two questions:
1) A WHERE clause is not working consistently?
2) I'd like to know who to group weekly data into quarterly data.
1) I've got a WHERE clause in some code that is not filtering the results I want by the SubCategory selected.
I tested the WHERE clause on shorter code (below) and it gave the top 10 results in the Yogurt SubCategory from the Enterprise Structure View, as expected.
select top 10 * from v_EnterpriseStructure
where SubCategoryName = 'Yogurt'
However, when I ran this code, which returns Price Zone ID, Price Zone Name, Client Department ID, etc, it returns the data for all SubCategories, instead of JUST Yogurt. Does anyone know why this could be?
select
pz.PriceZoneID,
pz.Name,
es.ClientDepartmentID,
es.DepartmentName,
es.ClientCategoryID,
es.CategoryName,
es.ClientSubCategoryID,
es.SubCategoryName,
es.ClientProductID,
es.ProductName,
ash.Sales as Units,
ash.price * ash.Sales as CashSales,
ash.Cost,
CAST(ash.date as Date) as Date
from aggregatedsaleshistory as ash
join v_EnterpriseStructure as es on es.ProductSID = ash.ProductSID
join PriceZone as pz on pz.PriceZoneID = ash.PriceZoneID
WHERE es.SubCategoryName = 'Yogurt'
GROUP BY
pz.PriceZoneID,
pz.Name,
es.ClientDepartmentID,
es.DepartmentName,
es.ClientCategoryID,
es.CategoryName,
es.ClientSubCategoryID,
es.SubCategoryName,
es.ClientProductID,
es.ProductName,
ash.Cost,
ash.Date
2) I'd posted a question about this last week, along with a question about why some code wasnt working.
Although the question about why the code wasn't working was answered, the question about grouping the data into quarters wasn't quite answered.
With the quarterly question, I'd like to return the results from the data the long query in Q1 above returns (currently in weekly format, as the dates are all weekly dates) into quarterly format.
Does anyone know how to do that?
Thanks in advance.

Customer Attrition in SQL Server

I am trying to find churned customer in the adventureworks2012 sample database. Churned customer in my case is a customer who used to be active in a period of six months, then has not made any transaction in a later period of time.
My attributes are customer ID, product category, product subcategories, price, order dates, online order flag etc
Can you please provide some hints on how to define teacher customer as either churned or not churned.
Thank you in advance.
If you're trying to loop through them all:
SELECT TEACHER_ID, MAX(ORDER_DATE) FROM ORDERS GROUP BY TEACHER_ID
Will give you each teachers last order date, and then you can loop through and compare them to whatever date range you want (if you're doing a loop).
If you're trying to figure out an individual teacher just see if the count is > 0:
SELECT COUNT(*) AS COUNT FROM ORDERS WHERE TEACHER_ID = ? AND ORDER_DATE > (NOW() - INTERVAL 6 MONTH)
Best I can do w\o a better idea what language you're using and what the application is.

SQL SELECT DISTINCT for dynamic data

Need a little help if possible:
Got data as follows , but this is filtered , the INQUIRYID column is what i am trying to work with as this is the Inquiry Number of the booking:
The last column has the number of nights in I am trying to calculate using Excel 2007.
The Column INQ_DATE are the booked nights for the hotel stay , in this case , this enquiry is for 2 nights. Each booking has the amount of lines on it which equals the amount of nights they are staying for.
A second booking is as follows:
7 lines - INQUIRYID = 9501
This booking is for 7 nights , which differs from the first one above of 2 nights.
In the column at the end , i need to calculate the nights , on the filtered data .
there are two tables involved :
BOOKING_INQUIRY
BOOKING_INQUIRY_ROOMS
Linked on : INQUIRYID
So far i have:
In SQL(Which works but has specified a specific INQUIRYID)
SELECT DISTINCT COUNT(INQUIRYID)FROM dbo.BOOKING_INQUIRY_ROOMS
WHERE
inquiryid = '9501'
This returns 7
I know i am nearly there and need to adapt the WHERE clause , to maybe a dynamic parameter , but cant for the life of me how...
Can anyone help me please?
Thanks,
Matt
SELECT
inquiryid,
COUNT(*) as Nights
FROM
dbo.BOOKING_INQUIRY_ROOMS
GROUP BY
inquiryid
Just use GROUP BY...

T-SQL rolling twelve month per day performance

I have checked similar problems, but none have worked well for me. The most useful was http://forums.asp.net/t/1170815.aspx/1, but the performance makes my query run for hours and hours.
I have 1.5 million records based on product sales (about 10k product) over 4 years. I want to have a table that contains date, product and rolling twelve months sales.
This query (from the link above) works, and shows what I want, but the perfomance makes it useless:
select day_key, product_key, price, (select sum(price) as R12 from #ORDER_TURNOVER as tb1 where tb1.day_key <= a.day_key and tb1.day_key > dateadd(mm, -12, a.day_key) and tb1.product_key = a.product_key) as RSum into #hejsan
from #ORDER_TURNOVER as a
I tried a rolling sum cursor function for all records which was fast as lightning, but I couldn't get the query only to sum the sales over the last 365 days.
Any ideas on how to solve this problem is much appreciated.
Thank you.
I'd change your setup slightly.
First, have a table that lists all the product keys that are of interest...
CREATE TABLE product (
product_key INT NOT NULL,
price INT,
some_fact_data VARCHAR(MAX),
what_ever_else SOMEDATATYPE,
PRIMARY KEY CLUSTERED (product_key)
)
Then, I'd have a calendar table, with each individual date that you could ever need to report on...
CREATE TABLE calendar (
date SMALLDATETIME,
is_bank_holdiday INT,
what_ever_else SOMEDATATYPE,
PRIMARY KEY CLUSTERED (date)
)
Finally, I'd ensure that your data table has a covering index on all the relevant fields...
CREATE INDEX IX_product_day ON #ORDER_TURNOVER (product_key, day_key)
This would then allow the following query...
SELECT
product.product_key,
product.price,
calendar.date,
SUM(price) AS RSum
FROM
product
CROSS JOIN
calendar
INNER JOIN
#ORDER_TURNOVER AS data
ON data.product_key = product.product_key
AND data.day_key > dateadd(mm, -12, calendar.date)
AND data.day_key <= calendare.date
GROUP BY
product.product_key,
product.price,
calendar.date
By doing everything in this way, each product/calendar_date combination will then relate to a set of record in your data table that are all consecutive to each other. This will make the act of looking up the data to be aggregated much, much simpler for the optimiser.
[Requires a single index, specifically in the order (product, date).]
If you have the index the other way around, it is actually much harder...
Example data:
product | date date | product
---------+------------- ------------+---------
A | 01/01/2012 01/01/2012 | A
A | 02/01/2012 01/01/2012 | B
A | 03/01/2012 02/01/2012 | A
B | 01/01/2012 02/01/2012 | B
B | 02/01/2012 03/01/2012 | A
B | 03/01/2012 03/01/2012 | B
On the left oyu just get all the records that are next to each other in a 365 day block.
On the right you search for each record before you can aggregate. The search is relatively simple, but you do 365 of them. Much more than the version on the left.
This is how one does "running totals" / "sum subsets" in SQL Server 2005-2008. In SQL 2012 there is native support for running totals but we are all still working with 2005-2008 db's
SELECT day_key ,
product_key ,
price ,
( SELECT SUM(price) AS R12
FROM #ORDER_TURNOVER AS tb1
WHERE tb1.day_key <= a.day_key
AND tb1.day_key > DATEADD(mm, -12, a.day_key)
AND tb1.product_key = a.product_key
) AS RSum
INTO #hejsan
FROM #ORDER_TURNOVER AS a
A few suggestions.
You could pre calculate the running totals so that they are not calculated again and again. What you are doing it the above select is a disguised loop and not a set query (unless the optimizer can convert the subquery to a join).
The above solution requires a few changes to the code.
Another solution that you can certainly try is to create a clustered index on your #ORDER_TURNOVER temp table. This is safer cause it's local change.
CREATE CLUSTERED INDEX IndexName
ON #ORDER_TURNOVER (day_key,day_key,product_key)
All your 3 expressions in the WHERE clause are SARGS so chanes are good that the optimizer will now do a seek instead of a scan.
If the index solution does not give enough performance gains that its well worth investing in solution 1

Resources