Grouping by two parameters in SQL Server - sql

I have a table with this structure:
id | timestamp | barcode
The timestamp is datetime and the barcode is a full barcode, from which I need only the first 9 digits.
I need to get the count for each product for each day with one query.
So I basically need a result like:
date | item number | count
-----------+-------------+--------
12.02.2019 | 827384950 | 32
Item number is left(barcode, 9).

You can try below - using cast() to convert timestamp to date and then add that in group by
select cast([timestamp] as date),left(barcode, 9) as itemnumber,count(*)
from tablename
group by cast([timestamp] as date),left(barcode, 9)

this query has better performance
select date, itemnumber, count(*) from
(select cast([timestamp] as date) as date,left(barcode, 9) as itemnumber
from tablename) a
group by date,itemnumber

Related

How do I create a new column showing difference between maximum date in table and date in row?

I need two columns: 1 showing 'date' and the other showing 'maximum date in table - date in row'.
I kept getting a zero in the 'datediff' column, and thought a nested select would work.
SELECT date, DATEDIFF(max_date, date) AS datediff
(SELECT MAX(date) AS max_date
FROM mytable)
FROM mytable
GROUP BY date
Currently getting this error from the above code : mismatched input '(' expecting {, ';'}(line 2, pos 2)
Correct format in the end would be:
date | datediff
--------------------------
2021-08-28 | 0
2021-07-26 | 28
2021-07-23 | 31
2021-08-11 | 17
If you want the date difference, you can use:
SELECT date, DATEDIFF(MAX(date) OVER (), date) AS datediff
FROM mytable
GROUP BY date
You can do this using the analytic function MAX() Over()
SELECT date, MAX(date) OVER() - date FROM mytable;
Tried this here on sqlfiddle

Select count for each specific date

I have the following need:
I need to count the number of times each id activated from all dates.
Let's say the table looks like this:
tbl_activates
PersonId int,
ActivatedDate datetime
The result set should look something like this:
counted_activation | ActivatedDate
5 | 2009-04-30
7 | 2009-04-29
5 | 2009-04-28
7 | 2009-04-27
... and so on
Anyone know how to do this the best possible way? The date comes in the following format '2011-09-06 15:47:52.110', I need to relate only to the date without the time. (summary for each date)
you can use count(distinct .. )
and if the ActivatedDate is datetime you can get the date part
select Cast(ActivatedDate AS date), count(distinct id)
from my_table
group by ast(ActivatedDate AS date)
You can use to_char function to remove the time from date
select count(*) counted_activation,
to_char(activatedDate,"yyyy-mm-dd") ActDate
from table1
group by to_char(activatedDate,"yyyy-mm-dd");
Use 'GROUP BY' and 'COUNT'. Use CONVERT method to convert datetime to Date only
SELECT CONVERT(DATE,activatedate), COUNT(userId)
FROM [table]
GROUP BY CONVERT(DATE,InvoiceDate)

Counting an already counted column in SQL (db2)

I'm pretty new to SQL and have this problem:
I have a filled table with a date column and other not interesting columns.
date | name | name2
2015-03-20 | peter | pan
2015-03-20 | john | wick
2015-03-18 | harry | potter
What im doing right now is counting everything for a date
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
what i want to do now is counting the resulting lines and only returning them if there are less then 10 resulting lines.
What i tried so far is surrounding the whole query with a temp table and the counting everything which gives me the number of resulting lines (yeah)
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
)
select count(*)
from temp_count
What is still missing the check if the number is smaller then 10.
I was searching in this Forum and came across some "having" structs to use, but that forced me to use a "group by", which i can't.
I was thinking about something like this :
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
)
select *
from temp_count
having count(*) < 10
maybe im too tired to think of an easy solution, but i can't solve this so far
Edit: A picture for clarification since my english is horrible
http://imgur.com/1O6zwoh
I want to see the 2 columned results ONLY IF there are less then 10 rows overall
I think you just need to move your having clause to the inner query so that it is paired with the GROUP BY:
with temp_count (date, counter) as
(
select date, count(*)
from testtable
where date >= current date - 10 days
group by date
having count(*) < 10
)
select *
from temp_count
If what you want is to know whether the total # of records (after grouping), are returned, then you could do this:
with temp_count (date, counter) as
(
select date, counter=count(*)
from testtable
where date >= current date - 10 days
group by date
)
select date, counter
from (
select date, counter, rseq=row_number() over (order by date)
from temp_count
) x
group by date, counter
having max(rseq) >= 10
This will return 0 rows if there are less than 10 total, and will deliver ALL the results if there are 10 or more (you can just get the first 10 rows if needed with this also).
In your temp_count table, you can filter results with the WHERE clause:
with temp_count (date, counter) as
(
select date, count(distinct date)
from testtable
where date >= current date - 10 days
group by date
)
select *
from temp_count
where counter < 10
Something like:
with t(dt, rn, cnt) as (
select dt, row_number() over (order by dt) as rn
, count(1) as cnt
from testtable
where dt >= current date - 10 days
group by dt
)
select dt, cnt
from t where 10 >= (select max(rn) from t);
will do what you want (I think)

T-SQL Convert DateTime and Count entries for each date

I am lost on how to solve what I believe should be a simple query.
I want to count the number of entries for each date in a table. The column DateCreated is in DateTime format. I can convert the datetime to date using
convert(VARCHAR, JobApps.DateCreated, 2) as Date
but with COUNT(ID) as Qty I get a count of 1 with multiple "Date" rows.
Here is the SQL query I am using.
SELECT
convert(VARCHAR, DateCreated, 2) as Date, COUNT(CompanyName) as Qty
FROM Apps
GROUP BY DateCreated
ORDER BY DateCreated DESC
This is the results I get.
Date Qty
------------------
13.05.29 1
13.05.29 1
13.05.29 1
13.05.29 1
13.05.29 1
13.05.28 1
13.05.28 1
13.05.27 1
13.05.27 1
etc...
What I wanting is a result like this...
Date Qty
-----------------
13.05.29 5
13.05.28 2
13.05.27 2
etc...
Just gotta change your GROUP BY to use the actual value you want:
SELECT convert(VARCHAR, DateCreated, 2) as Date, COUNT(1) as Qty
FROM Apps
GROUP BY convert(VARCHAR, DateCreated, 2)
ORDER BY Date DESC

Modulo Time in SQL Server 2005 - Return data every n hours

I have something like this:
SELECt *
FROM (
SELECT prodid, date, time, tmp, rowid
FROM live_pilot_plant
WHERE date BETWEEN CONVERT(DATETIME, '3/19/2012', 101)
AND CONVERT(DATETIME, '3/31/2012', 101)
) b
WHERE b.rowid % 400 = 0
FYI: The reason for the convert in the where clause, is because my date is stored as a varchar(10), I had to convert it to datetime in order to get the correct range of data. (I tried a bunch of different things and this worked)
I'm wondering how I can return the data I want every 4 hours during those selected dates. I have data collected approximately every 5 seconds (with some breaks in data) - ie data wasn't collected during a 2 hour period, but then continues at 5 second increments.
In my example I just used a modulo with my rowid - and the syntax works, but as I mentioned above there are some periods where data isnt collected so using logic like: if you take data every 5 seconds and multiple that by 4 hours you can approximately say how many rows are in between wont work.
My time column is a varchar column and is in the form hh:mm:ss
My ideal output is:
| prodid | date | time | tmp |
| 4 | 3/19/2012 | 10:00:00 | 2.3 |
| 7 | 3/19/2012 | 14:00:24 | 3.2 |
As you can see I can be a bit off (in terms of seconds) - I more so need the approximate value in terms of time.
Thank you in advance.
This should work
select prodid, date, time, tmp, rowid
from live_pilot_plant as lpp
inner join (
select min(prodid) as prodid -- is prodid your PK?? if not change it to rowid or whatelse is your PK
from live_pilot_plant
WHERE date BETWEEN CONVERT(DATETIME, '3/19/2012', 101) -- or whatever you want
AND CONVERT(DATETIME, '3/31/2012', 101) -- for better performance it is on the inner select
group by date,
floor( -- floor makes the trick
convert(float,convert(datetime, time)) -- assumes "time" column is a varchar containing data like '19:23:05'
* 6 -- 6 comes form 24 hours / 4 hours
)
) as filter on lpp.prodid = filter.prodid -- if prodid is not the PK also correct here.
A side note for everyone else who have date + time data in only one datetime field, suppose named "when_it_was", the group by can be as simple as:
group by floor(when_it_was * 6) -- again, 6 comes from 24/4
something along the lines of the following should work. Basically create date + time partitions, each partition representing a block of 4 hours and pick the record with the highest rank from each partition
select * from (
select *,
row_number() over (partition by date,cast(left( time, charindex( ':', time) - 1) as int) / 4 order by
date, time) as ranker from live_pilot_plant
) Z where ranker = 1
Assuming rowid is a PK and increased with date/time. Just convert time field to 4 hours interval number substring(time,1,2))/4 and select MIN(rowid) from each of 4 hours groups in a day:
select prodid, date, time, tmp, rowid from live_pilot_plant where rowid in
(
select min(rowid)
from live_pilot_plant
WHERE CONVERT(DATETIME, date, 101) BETWEEN CONVERT(DATETIME, '3/19/2012', 101)
AND CONVERT(DATETIME, '3/31/2012', 101)
group by date,convert(int,substring(time,1,2))/4
)
order by CONVERT(DATETIME, date, 101),time