A tricky query to update the table with values of another table - sql-server

This question is an extension of my previous one available at Unable know the exception in query.
This time I've Another table named breaks.
And it looks like below.
I'm able to get the column sum using the below query.
SELECT DATEADD(SECOND, SUM(DATEDIFF(SECOND, '19000101', TotalBreakTime)), '19000101') where
where USERID = 0138039 AND CONVERT(Date, StartTime) = CONVERT(Date, GETDATE()))
as t FROM BreaksTable;
My second table looks like below.
This time, I want to update the breaks column with the sum of the totalbreaktime from Breaks table(the first screenshot) and the condition has to be the date is to be current day.
I'm really unable to understand how to do this.

You need MERGE:
MERGE SecondTable as target
USING (
SELECT USERID,
SUM(DATEDIFF(SECOND, '19000101', TotalBreakTime)) as ColumnWithBreaksCount
FROM BreaksTable
where CONVERT(Date, StartTime) = CONVERT(Date, GETDATE()))
GROUP BY USERID) as source
ON target.USERID = source.USERID
WHEN MATCHED THEN UPDATE
SET BREAKS = source.ColumnWithBreaksCount
But this will work only if you have only one column for each USERID in your secondtable, else you need to add another key kolumn in ON part of query, which will help to make rows unique.

Related

Order by time part only

When I select time in SQL it is returned as 2011-02-25 21:17:33.933. But I need only the time part. How can I do this? I'm trying to: order by "Onlie Duration" DESc , but need it to be ordered by time
You can do something like this:
SELECT time_column FROM dbo.table
ORDER BY CONVERT(time, time_column)
You can get only the time part using:
select convert(char,[YourDateColumn],108) from [YourTable]
Sorting your data based on time can be done by ordering using:
select * from [YourTable] order by convert(char,[yourDateColumn],108)
The downside to this is that, sorting with just the time when there are dates for different days will mix the time for the various days.
Use Convert function
SELECT * FROM MyTable
ORDER BY CONVERT(varchar(10), TimeField, 108)
UPD Or using DATEDIFF:
SELECT * FROM MyTable
ORDER BY DATEDIFF(MILLISECOND, CAST(TimeField AS DATE), TimeField)

SQL Server : convert datetime in place in table

Basically I inherited a rather large table which has a few columns with dates formatted as varchar(10) of '##.##.####' (day.month.year). I would like to convert these columns to Datetime columns for that specific date.
Is there anyway to convert these in place on SQL Server (through a single set of SQL queries), instead of SELECTing each record in some programming language, converting the date and then UPDATEing back as Datetime (perhaps to a different column)?
There is no need in ...=(select...) The action is simple and straightforward.
ALTER TABLE YourTable
ADD NewDateColumn DATETIME
update YourTable set NewDateColumn = convert(date, OldDateColumn, 104)
--Magic 104 is for dd.MM.yyyy date format
That's all.
How about this as an alternative to Jim's comment. First add new DATE column:
ALTER TABLE YourTable
ADD NewDateColumn DATETIME
Then to UPDATE (I suppose you would want to use the same standard you've been using):
UPDATE t
SET t.NewDateColumn = (SELECT CONVERT(DATE, OldDateColumn, 104)
FROM YourTable ta WHERE t.ID = ta.ID)
FROM YourTable t
For someone that might want to get it from the German standard to the U.S. standard:
UPDATE t
SET t.NewDateColumn = (SELECT CONVERT(DATETIME,
CONVERT(DATE, OldDateColumn, 104)
,101)
FROM YourTable ta WHERE t.ID = ta.ID)
FROM YourTable t
This is assuming you do have an ID column.

SQL Server : select data between date range where there is missing data

Using SQL Server 2012, I have a script that inserts 4 rows of data into a table each day. The data looks like this:
Sometimes one or more of the rows is not inserted as the source data is incomplete. This looks like this - the second column is called commodityID:
There are times where more than one row could be missing.
I am trying to write a query that will show me what data is missing, so for the example above it would be for commodityID = 2. I have another table which is a calendar (lists all dates) table which I use with the query below to see if no data exists for a given date for all commodities.
SELECT *
FROM [Calendar]
WHERE (NOT EXISTS (SELECT ID, CommodityID, Price, DateEntered
FROM Spectron_DailyPricing
WHERE (CONVERT(date, DateEntered) = Calendar.date)))
AND (date BETWEEN '2015-05-14' AND dateadd(day, -1,GETDATE()))
ORDER BY date asc
I want to be able to run a SQL query that will look through all of the data and show the date and the commodityID that is missing. So for the example above it would show the following.
As my data spans a few years and there is the odd missing row there would be numerous results.
WITH
CTE_Numbers AS (
SELECT * FROM (VALUES (1),(2),(3),(4)) AS a(CommodityID)),
CTE_Calendar AS (
SELECT *
FROM [Calendar] c
CROSS JOIN CTE_Numbers n
WHERE c.date BETWEEN '2015-05-14' AND dateadd(day, -1,GETDATE()))
SELECT *
FROM CTE_Calendar c
LEFT JOIN Spectron_DailyPricing s
ON c.CommodityID = s.CommodityID
AND c.date = CONVERT(date, s.DateEntered)
WHERE
s.CommodityID IS NULL
ORDER BY c.date asc

Select newest datetime for each userid MS Sql Server

I have a table used for a chat. Among others there is a field called userid and a field called timesent. I need to know the latest timesent for each userid in the table, so that I can delete them from the table if they haven't said anything for 3 minutes, in which case I will assume they are gone.
I can't really crack this nut... How do I query.
I could of course split it up and first select all the userids and then loop through them and select top 1 timesent in my method, but I was wondering if sql alone can do the trick, so I don't need to execute tons of queries.
To get the latest timesent per userid you can use MAX
SELECT userid, MAX(timesent) AS timesent
FROM your_table
GROUP BY userid
Or to do the specified delete you can use
DELETE your_table
FROM your_table y1
WHERE NOT EXISTS(SELECT *
FROM your_table y2
WHERE y2.userid = y1.userid
AND y2.timesent >= DATEADD(MINUTE, -3, GETDATE()))

How can I optimize a SQL query that performs a count nested inside a group-by clause?

I have a charting application that dynamically generates SQL Server queries to compute values for each series on a given chart. This generally works quite well, but I have run into a particular situation in which the generated query is very slow. The query looks like this:
SELECT
[dateExpr] AS domainValue,
(SELECT COUNT(*) FROM table1 WHERE [dateExpr]=[dateExpr(maintable)] AND column2='A') AS series1
FROM table1 maintable
GROUP BY [dateExpr]
ORDER BY domainValue
I have abbreviated [dateExpr] because it's a combination of CAST and DATEPART functions that convert a datetime field to a string in the form of 'yyyy-MM-dd' so that I can easily group by all values in a calendar day. The query above returns both those yyyy-MM-dd values as labels for the x-axis of the chart and the values from the data series "series1" to display on the chart. The data series is supposed to count the number of records that fall into that calendar day that also contain a certain value in [column2]. The "[dateExpr]=[dateExpr(maintable)]" expression looks like this:
CAST(DATEPART(YEAR,dateCol) AS VARCHAR)+'-'+CAST(DATEPART(MONTH,dateCol) AS VARCHAR) =
CAST(DATEPART(YEAR,maintable.dateCol) AS VARCHAR)+'-'+CAST(DATEPART(MONTH,maintable.dateCol) AS VARCHAR)
with an additional term for the day (ommitted above for the sake of space). That is the source of the slowness of the query, but I don't know how to rewrite the query so that it returns the same result more efficiently. I have complete control over the generation of the query, so if I could find more efficient SQL that returned the same results, I could modify the query generator appropriately. Any pointers would be greatly appreciated.
I havent tested but i think it can be done by:
SELECT
[dateExpr] AS domainValue,
SUM (CASE WHEN column2='A' THEN 1 ELSE 0 END) AS series1
FROM table1 maintable
GROUP BY [dateExpr]
ORDER BY domainValue
The fastest way to do this would be to use calendar tables. Create a sql table with an entry for every month for next who knows how many years. Then select from that calendar table, joining in the entries from table1 that have dates between the start and end date for the month. Then, if your clustered index is on the dateCol in table1, the query will run very quickly.
EDIT: Example Query. This assumes a months table exists with two columns, StartDate and EndDate where EndDate is the midnight on the first day of the next month. The clustered index on the months table should be on StartDate
SELECT
months.StartDate,
COUNT(*) AS [Count]
FROM months
INNER JOIN table1
ON table1.dateCol >= months.StartDate AND table1.dateCol < months.EndDate
GROUP BY months.StartDate;
With Calendar As
(
Select DateAdd(d, DateDiff(d, 0, Min( dateCol ) ), 0) As [date]
From Table1
Union All
Select DateAdd(d, 1, [date])
From Calendar
Where [date] <= (
Select Max( DateAdd(d, DateDiff(d, 0, dateCol) + 1, 0) )
From Table1
)
)
Select C.date, Count(Table1.PK) As Total
From Calendar As C
Left Join Table1
On Table1.dateCol >= C.date
And Table1.dateCol < DateAdd(d, 1, C.date )
And Table1.column2 = 'A'
Group By C.date
Option (Maxrecursion 0);
Rather than try to force the display format in SQL, you should do that in your report or chart generator. However, what you can do in the SQL is to strip the time portion from the datetime values as I've done in my solution.

Resources