Max(datetime) ignore seconds - sql-server

I got my sql query working but when I find a date with the same hour and minutes, I am not able to make the query works. For example:
On the column "trans_date" I can't use my query because with max(trans_date) I am getting no results, somehow the sql is ignoring the seconds.
This is my complete sql sentence:
SELECT till.code,art.description
FROM [TCPOS4].[dbo].[transactions] as tra,
TCPOS4.dbo.articles as art,[TCPOS4].[dbo].[trans_articles] as tro,
[TCPOS4].[dbo].[tills] as till,[TCPOS4].[dbo].[shops] as shop
where tra.till_id=till.id and shop.id=till.shop_id and tro.transaction_id=tra.id and
art.id=tro.article_id and tra.trans_date =(select max(trans_date)
from tcpos4.dbo.transactions as t2 where t2.till_id=tra.till_id and trans_date > '2016-10-26 00:00:0.000' and trans_date< '2016-10-27 00:00:00.000' )
group by till.code,art.description
With this query I am getting for each "code" from the 2016-10-26 to 2016-10-27 the max transaction_date, but I am not getting any information from the code "5446". I should get "TABLE CHOCOLECHE-CONGUITOS" because it's the max trans_date in the range.

Can you try with a different approach like the following?
SELECT code, description
FROM
(
SELECT till.code, art.description,
row_number() OVER (PARTITION BY till.code ORDER BY trans_date DESC) RowNum
FROM [TCPOS4].[dbo].[transactions] AS tra
LEFT JOIN [TCPOS4].[dbo].[tills] AS till
ON tra.till_id=till.id
LEFT JOIN [TCPOS4].[dbo].[shops] AS shop
ON shop.id=till.shop_id
LEFT JOIN [TCPOS4].[dbo].[trans_articles] AS tro
ON tro.transaction_id=tra.id
LEFT JOIN TCPOS4.dbo.articles AS art
ON art.id=tro.article_id
) sbt
WHERE RowNum=1
In this way you will get one result for each till.code even if you have the same exact date.
You can add more fields in the ORDER BY if needed.
EDIT: removed art.description in PARTITION BY.
EDIT 2: converted with LEFT JOIN

try
...CAST(tra.trans_date AS DATE) = (select CAST(max(trans_date) AS DATE)...

Related

AdventureWorks in SQL Server 2019 : ordershare percent for each item per month

I'm new to SQL Server. I'm trying to write a code to find the sale percent/per item/per month. Something like this:
Year
Month
ProductID
Order_Quantity_Per_Month
Total_Sold_Per_Month
%_Of_Total_Sale
2011
5
707
422
17024
2
First and most importantly, I want to write this code with "CTE" and "Group by". I've tried many times but I failed. How can I write this code with cte and group by?
I wrote this code with "Over" and "Partition". Could someone check the codes I've written to see if it's actually correct:
USE AdventureWorks2019
GO
SELECT
YEAR (soh.OrderDate) As Year,
MONTH (soh.OrderDate) As Month,
pro.productid AS [Product ID],
pro.Name AS [Product Name],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate) ORDER BY by soh.OrderDate) AS [Order Quantity Per Month],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate)) AS [Total Sold Per Month],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate) ORDER BY by soh.OrderDate) * 100 / SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate)) AS [% of TotalSale]
FROM
Production.Product pro
INNER JOIN
Sales.SalesOrderdetail sod ON pro.ProductID = sod.ProductID
INNER JOIN
Sales.SalesOrderheader soh ON soh.SalesOrderID = sod.SalesOrderID
GROUP BY
YEAR(soh.OrderDate), MONTH(soh.OrderDate),
soh.OrderDate, pro.productid, pro.Name, sod.OrderQty
ORDER BY
Year, Month
If the above code is correct, How can I write the code with cte and group by?
I think the better question is why you want (or need) to use a CTE. A simple CTE (i.e., not recursive) is just syntactic sugar for a derived table. There is nothing particular special or complicated about writing and using one in a query. If you "tried many times", you should have included those attempts in your question.
But to satisfy the need to use a CTE, you can simply "cram" the query you have into the CTE and select rows from it. Example:
with cteOrders as (
select ... -- your original query here without ORDER BY clause
)
select * from cteOrders
order by [Year], [Month]
;
That is a extremely simplistic way of using a CTE. There is no real or obvious advantage to doing so but it does satisfy your goal. Because of that, I smell a XY problem.

How do I properly add this query into my existing query within Query Designer?

I currently have the below query written within Query Designer. I asked a question yesterday and it worked on its own but I would like to incorporate it into my existing report.
SELECT Distinct
i.ProductNumber
,i.ProductType
,i.ProductPurchaseDate
,ih.SalesPersonComputerID
,ih.SalesPerson
,ic2.FlaggedComments
FROM [Products] i
LEFT OUTER JOIN
(SELECT Distinct
MIN(c2.Comments) AS FlaggedComments
,c2.SalesKey
FROM [SalesComment] AS c2
WHERE(c2.Comments like 'Flagged*%')
GROUP BY c2.SalesKey) ic2
ON ic2.SalesKey = i.SalesKey
LEFT JOIN [SalesHistory] AS ih
ON ih.SalesKey = i.SalesKey
WHERE
i.SaleDate between #StartDate and #StopDate
AND ih.Status = 'SOLD'
My question yesterday was that I wanted a way to select only the first comment made for each sale. I have a query for selecting the flagged comments but I want both the first row and the flagged comment. They would both be pulling from the same table. This was the query provided and it worked on its own but I cant figure out how to make it work with my existing query.
SELECT a.DateTimeCommented, a.ProductNumber, a.Comments, a.SalesKey
FROM (
SELECT
DateTimeCommented, ProductNumber, Comments, SalesKey,
ROW_NUMBER() OVER(PARTITION BY ProductNumber ORDER BY DateTimeCommented) as RowN
FROM [SalesComment]
) a
WHERE a.RowN = 1
Thank you so much for your assistance.
You can use a combination of row-numbering and aggregation to get both the Flagged% comments, and the first comment.
You may want to change the PARTITION BY clause to suit.
DISTINCT on the outer query is probably spurious, on the inner query it definitely is, as you have GROUP BY anyway. If you are getting multiple rows, don't just throw DISTINCT at it, instead think about your joins and whether you need aggregation.
The second LEFT JOIN logically becomes an INNER JOIN due to the WHERE predicate. Perhaps that predicate should have been in the ON instead?
SELECT
i.ProductNumber
,i.ProductType
,i.ProductPurchaseDate
,ih.SalesPersonComputerID
,ih.SalesPerson
,ic2.FlaggedComments
,ic2.FirstComments
FROM [Products] i
LEFT OUTER JOIN
(SELECT
MIN(CASE WHEN c2.RowN = 1 THEN c2.Comments) AS FirstComments
,c2.SalesKey
,MIN(CASE WHEN c2.Comments like 'Flagged*%' THEN c2.Comments) AS FlaggedComments
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ProductNumber ORDER BY DateTimeCommented) as RowN
FROM [SalesComment]
) AS c2
GROUP BY c2.SalesKey
) ic2 ON ic2.SalesKey = i.SalesKey
JOIN [SalesHistory] AS ih
ON ih.SalesKey = i.SalesKey
WHERE
i.SaleDate between #StartDate and #StopDate
AND ih.Status = 'SOLD'

How to self join a CTE?

Hi This is the query i have created to fetch records from a history table This query is working fine but taking too much time to execute because it is selecting data twice from the table and the table has 20 millon or above records. So i want to optimize it. I will try to explain what this query does and what i want to achieve.
I want to select two rows for each Id (ActivityId) from the table first is where the data is min and second where the date is maximum, So i can see how much progress happened in the mean time. Now what i am doing is first selecting the data where date is min as CTE and then selecting the data where date is maximum as CTE2. I can select both rows in a single CTE but I am not able to get a single record from both rows. Like i only need the Progress and Planned Field from the maximum date row and select all the other fields (most fields are common on both rows). So how can i achieve this. and please ask for clarification if needed.
CTE:
WITH cte AS
(
SELECT Row_number() OVER (partition BY pmaph.activityid ORDER BY date) r1,
pma.planenddate AS planenddate ,
pma.planstartdate AS planstartdate,
pmaph.activityid,
pmaph.projectmilestoneactivproghist_id AS promileavtiid,
umd.uom_name AS uomname,
pmm.milestonename AS milestonename,
pma.activityname AS activityname ,
pmp.projectname AS projectname,
Replace((Rtrim(Ltrim(CONVERT(VARCHAR(12),Cast(pmaph.date AS DATETIME),106)))),' ','-') AS rdate,
Isnull(pmaph.actual_progress,0) AS actualprogress,
Isnull(pmaph.planned_progress,0) AS plannedprogress
FROM projectmilestoneactivityprogresshistory AS pmaph
LEFT JOIN dbo.pm_project AS pmp
ON pmaph.projectid=pmp.projectid
LEFT JOIN dbo.pm_activity AS pma
ON pmaph.activityid=pma.activityid
LEFT JOIN dbo.pm_milestone AS pmm
ON pmaph.milestoneid=pmm.milestoneid
LEFT JOIN dbo.uomdetail AS umd
ON pma.uom_id=umd.uom_id
WHERE pmaph.client_id=1030), cte2 AS( r2,isnull(pmaph.actual_progress,0) AS actualprogress, isnull(pmaph.planned_progress,0) AS plannedprogress, replace((rtrim(ltrim(CONVERT(varchar(12), cast(pmaph.date AS datetime),106)))),' ','-') AS rdate,pmaph.activityid FROM projectmilestoneactivityprogresshistory AS pmaph WHERE pmaph.client_id=1030)
SELECT cte2.rdate AS todate,
cte2.actualprogress AS end_actualprogress,
cte2.plannedprogress AS end_plannedprogress,
cte.actualprogress AS start_actualprogress,
cte.plannedprogress AS start_plannedprogress,
cte.rdate AS fromdate ,
cte.planenddate,
cte.planstartdate,
cte.activityid,
cte.uomname,
cte.milestonename,
cte.activityname,
cte.projectname
FROM cte
JOIN cte2
ON cte.activityid= cte2.activityid
WHERE cte.r1=1
AND cte2.r2=1

Replace Group By clause with any other clause

In below query, I am using GROUP BY clause to get list of recently updated records depends on updated date. But I would like to have the query without a GROUP BY clause because of some internal reasons. Can please any one help me to solve this.
SELECT Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress PP
WHERE Proj_UpdatedDate IN (SELECT MAX(Proj_UpdatedDate)
FROM ProjectProgress
GROUP BY
Proj_ProjectID)
ORDER BY
Proj_ProjectID
Using TOP 1 should give you the same result assuming you meant the MAX(Proj_UpdatedDate):
SELECT Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress PP
WHERE Proj_UpdatedDate IN (SELECT TOP 1 Proj_UpdatedDate
FROM ProjectProgress
ORDER BY Proj_UpdatedDate DESC)
ORDER BY
Proj_ProjectID
However your query actually returns multiple dates since it's GROUPED BY Proj_ProjectId (the max date for each project). Is that your desired outcome - to show a list of dates that the projects were updated and by whom?
If so, try using ROW_NUMBER():
SELECT Proj_UpdatedDate, Proj_UpdatedBy
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY Proj_ProjectID ORDER BY Proj_UpdatedBy DESC) rn,
Proj_UpdatedDate,
Proj_UpdatedBy
FROM ProjectProgress
) t
WHERE rn = 1
And here is the SQL Fiddle. This assumes you are running SQL Server 2005 or greater.
Good luck.

SQL Server last date

Is there an option for getting the row with the highest date without joining the same table and use max(date) ?? Is Top1 order by desc a valid option ?
I use SQL Server 2000. And performance is important.
edit:
Table1:
columns: part - partdesc
Table 2:
columns: part - cost - date
select a.part,partdesc,b.cost
left join( select cost,part
right join(select max(date),part from table2 group by part) maxdate ON maxdate.date = bb.date
from table2 bb ) b on b.part = a.part
from table1
I don't know if the code above works but that is the query I dislike. And seems to me inefficient.
Here's a somewhat simplified query based on your edit.
SELECT
a.part,
a.partdesc,
sub.cost
FROM
Table1 A
INNER JOIN
(SELECT
B.part,
cost
FROM
Table2 B
INNER JOIN
(SELECT
part,
MAX(Date) as MaxDate
FROM
Table2
GROUP BY
part) BB
ON bb.part = b.part
AND bb.maxdate = b.date) Sub
ON sub.part = a.part
The sub-sub query will hopefully run a little bit quicker than your current version since it'll run once for the entire query, not once per part value.
SELECT TOP 1 columnlist
FROM table
ORDER BY datecol DESC
is certainly a valid option, assuming that your datacols are precise enough that you get the results needed (in other words, if it's one row per day, and your date reflects that, then sure. If it's several rows per minute, you may not be precise enough).
Performance will depend on your indexing strategy and hardware.

Resources