How to return a count result of only one column? - select

I have a table like this:
And would like to make a selection by period (date field), where I could return the registers, and a column with the total of registres matched with only one column.
For example:
If I use this query:
SELECT date, product_type, operation, unit
FROM table
WHERE date BETWEEN '2019-08-26 00:00:00' AND '2019-08-26 23:59:59';
It must return:
But I wish I could return one more column, with the total of operations regardless period like this:
Where in this case, 6 is the frequency that "ajoy" appears in the table.
IMPORTANT! If I select a period where two or more operations are returned, so the query must be able to return their frequency as well.

I used part of your data and will include what I had for data in the table, but I believe this is what you want
create table mytab (job int, operations char(8), prod char(8),
ts_date datetime year to minute, unit int) lock mode row;
insert into mytab values(22, "ajoy","arrow","2020-05-11 08:51", 20);
insert into mytab values(22, "ajoy","arrow","2020-05-11 08:51", 20);
insert into mytab values(22, "ajoy","arrow","2020-05-11 08:51", 20);
insert into mytab values(22, "ajoy","arrow","2020-04-11 14:15", 20);
insert into mytab values(22, "ajoy","arrow","2020-04-11 14:15", 20);
insert into mytab values(22, "ajoy","arrow","2020-04-11 14:15", 20);
insert into mytab values(23, "dinn","curve","2020-05-11 08:51",1);
insert into mytab values(23, "dinn","point","2020-05-11 08:51",1);
insert into mytab values(23, "dinn","arrow","2020-04-11 08:51",1);
The query:
select job, operations, prod, ts_date, unit, (select count(*) from mytab b
where b.operations = a.operations) total_operation from mytab a where
a.ts_date between "2020-05-11 08:50" and "2020-05-11 08:59"
The above query gave me the following results which is I think what you were asking for:
job operations prod ts_date unit total_operation
22 ajoy arrow 2020-05-11 08:51 20 6
22 ajoy arrow 2020-05-11 08:51 20 6
22 ajoy arrow 2020-05-11 08:51 20 6
23 dinn curve 2020-05-11 08:51 1 3
23 dinn point 2020-05-11 08:51 1 3
This example is small and has doesn't include/account for indexes you may which to put on the table to speed query performance.

Related

How can I query concurrent events, i.e. usage, in postgres?

From my first table of events below, what query would give me my second table of usage?
start
end
08:42
08:47
08:44
08:50
start
end
count
08:42
08:44
1
08:44
08:47
2
08:47
08:50
1
What if any indexes should I create to speed this up?
The main thing I often need is the peak usage and when it is (i.e. max count row from above), so also is there a quicker way to get one/both of these?
Also, is it quicker to query for each second (which I can imagine how to do), e.g:
time
count
08:42
1
08:43
1
08:44
2
08:45
2
08:46
2
08:47
1
08:48
1
08:49
1
NB my actual starts/ends are timestamp(6) with time zone and I have thousands of records, but I hope my example above is useful.
step-by-step demo:db<>fiddle
SELECT
t as start,
lead as "end",
sum as count
FROM (
SELECT
t,
lead(t) OVER (ORDER BY t), -- 2a
type,
SUM(type) OVER (ORDER BY t) -- 2b
FROM (
SELECT -- 1
start as t,
1 as type
FROM mytable
UNION
SELECT
stop,
-1 as type
FROM mytable
) s
) s
WHERE sum > 0 -- 3
Put all time values into one column. Add the 1 value to former start values and -1 to former end values
a) put the next time values into the current record b) use cumulative SUM() over the newly added 1/-1 value. Each start point increased the count, each end value decreased it. This is your expected count
Remove all records without an interval.
The above only works properly if your borders are distinct. If you have interval borders at the same time point, you have to change the UNION into UNION ALL (which keeps same values) and group this result afterwards to generate for example -2 from two -1 values at same time slot:
step-by-step demo:db<>fiddle
SELECT
t as start,
lead as "end",
sum as count
FROM (
SELECT
t,
lead(t) OVER (ORDER BY t),
type,
SUM(type) OVER (ORDER BY t)
FROM (
SELECT
t,
SUM(type) AS type
FROM (
SELECT
start as t,
1 as type
FROM mytable
UNION ALL
SELECT
stop,
-1 as type
FROM mytable
) s
GROUP BY t
) s
) s
WHERE sum > 0

CROSSTAB PostgreSQL - Alternative for PIVOT in Oracle

I'm migrating a query of Oracle pivot to PostgreSQL crosstab.
create table(cntry numeric,week numeric,year numeric,days text,day text);
insert into x_c values(1,15,2015,'DAY1','MON');
...
insert into x_c values(1,15,2015,'DAY7','SUN');
insert into x_c values(2,15,2015,'DAY1','MON');
...
values(4,15,2015,'DAY7','SUN');
I have 4 weeks with 28 rows like this in a table. My Oracle query looks like this:
SELECT * FROM(select * from x_c)
PIVOT (MIN(DAY) FOR (DAYS) IN
('DAY1' AS DAY1 ,'DAY2' DAY2,'DAY3' DAY3,'DAY4' DAY4,'DAY5' DAY5,'DAY6' DAY6,'DAY7' DAY7 ));
Result:
cntry|week|year|day1|day2|day3|day4|day4|day6|day7|
---------------------------------------------------
1 | 15 |2015| MON| TUE| WED| THU| FRI| SAT| SUN|
...
4 | 18 |2015| MON| ...
Now I have written a Postgres crosstab query like this:
select *
from crosstab('select cntry,week,year,days,min(day) as day
from x_c
group by cntry,week,year,days'
,'select distinct days from x_c order by 1'
) as (cntry numeric,week numeric,year numeric
,day1 text,day2 text,day3 text,day4 text, day5 text,day6 text,day7 text);
I'm getting only one row as output:
1|17|2015|MON|TUE| ... -- only this row is coming
Where am I doing wrong?
ORDER BY was missing in your original query. The manual:
In practice the SQL query should always specify ORDER BY 1,2 to ensure that the input rows are properly ordered, that is, values with the same row_name are brought together and correctly ordered within the row.
More importantly (and more tricky), crosstab() requires exactly one row_name column. Detailed explanation in this closely related answer:
Crosstab splitting results due to presence of unrelated field
The solution you found is to nest multiple columns in an array and later unnest again. That's needlessly expensive, error prone and limited (only works for columns with identical data types or you need to cast and possibly lose proper sort order).
Instead, generate a surrogate row_name column with rank() or dense_rank() (rnk in my example):
SELECT cntry, week, year, day1, day2, day3, day4, day5, day6, day7
FROM crosstab (
'SELECT dense_rank() OVER (ORDER BY cntry, week, year)::int AS rnk
, cntry, week, year, days, day
FROM x_c
ORDER BY rnk, days'
, $$SELECT unnest('{DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7}'::text[])$$
) AS ct (rnk int, cntry int, week int, year int
, day1 text, day2 text, day3 text, day4 text, day5 text, day6 text, day7 text)
ORDER BY rnk;
I use the data type integer for out columns cntry, week, year because that seems to be the (cheaper) appropriate type. You can also use numeric like you had it.
Basics for crosstab queries here:
PostgreSQL Crosstab Query
I got this figured out from http://www.postgresonline.com/journal/categories/24-tablefunc
select year_wk_cntry.t[1],year_wk_cntry.t[2],year_wk_cntry.t[3],day1,day2,day3,day4,day5,day6,day7
from crosstab('select ARRAY[country :: numeric,week,year] as t,days,min(day) as day
from x_c group by country,week,year,days order by 1,2
','select distinct days from x_c order by 1')
as year_wk_cntry (t numeric[],day1 text,day2 text,day3 text,
day4 text, day5 text,day6 text,day7 text);
thanks!!

Get Data From Postgres Table At every nth interval

Below is my table and i am inserting data from my windows .Net application at every 1 Second Interval. i want to write query to fetch data from the table at every nth interval for example at every 5 second.Below is the query i am using but not getting result as required. Please Help me
CREATE TABLE table_1
(
timestamp_col timestamp without time zone,
value_1 bigint,
value_2 bigint
)
This is my query which i am using
select timestamp_col,value_1,value_2
from (
select timestamp_col,value_1,value_2,
INTERVAL '5 Seconds' * (row_number() OVER(ORDER BY timestamp_col) - 1 )
+ timestamp_col as r
from table_1
) as dt
Where r = 1
Use date_part() function with modulo operator:
select timestamp_col, value_1, value_2
from table_1
where date_part('second', timestamp_col)::int % 5 = 0

Trigger Compilation Error, Oracle 11g

Banging my head up against this one for a while. I'm constructing a database on oracle 11g, and am attempting to insert a record into a "registry" table whenever a record is created on a "data product" table. The registry table needs to auto-increment the product_id, and then that product_id is used as a foreign key on the data product table. Here is my trigger code:
CREATE OR REPLACE TRIGGER "TR_CAMERA_DP_DPR_CREATE"
BEFORE INSERT ON "DD1"."CAMERA_DP"
FOR EACH ROW
BEGIN
:new.product_id := ID_SEQ.NEXTVAL;
insert into dd1.dp_registry
( product_id,
fs_location,
parent_group_id,
product_name,
shortdes,
createdate,
revision )
values
( :new.product_id,
'placeholder',
0,
'_image',
'description placeholder',
sysdate,
0
);
END;
So, ideally, an insert into dd1.camera_dp without providing a product_id will first insert a record into dd1.dp_registry, and then use that incremented product_id as the key field for dd1.camera_dp.
The insert statement works when run with a hard-coded value for :new.product_id, and ID_SEQ.NEXTVAL is also working properly. I get the feeling I'm missing something obvious.
Thanks!
Your code works perfectly well for me. If you're getting an error, there is something about the code that you are actually running from the code that you posted.
SQL> create table CAMERA_DP(
2 product_id number,
3 name varchar2(10)
4 );
Table created.
SQL> create sequence id_seq;
Sequence created.
SQL> ed
Wrote file afiedt.buf
1 create table dp_registry
2 ( product_id number,
3 fs_location varchar2(100),
4 parent_group_id number,
5 product_name varchar2(100),
6 shortdes varchar2(100),
7 createdate date,
8* revision number)
SQL> /
Table created.
SQL> ed
Wrote file afiedt.buf
1 CREATE OR REPLACE TRIGGER "TR_CAMERA_DP_DPR_CREATE"
2 BEFORE INSERT ON "CAMERA_DP"
3 FOR EACH ROW
4 BEGIN
5 :new.product_id := ID_SEQ.NEXTVAL;
6 insert into dp_registry
7 ( product_id,
8 fs_location,
9 parent_group_id,
10 product_name,
11 shortdes,
12 createdate,
13 revision )
14 values
15 ( :new.product_id,
16 'placeholder',
17 0,
18 '_image',
19 'description placeholder',
20 sysdate,
21 0
22 );
23* END;
24 /
Trigger created.
SQL> insert into camera_dp( name ) values( 'Foo' );
1 row created.
SQL> ed
Wrote file afiedt.buf
1* select product_id from dp_registry
SQL> /
PRODUCT_ID
----------
1
If you're getting an error that a table doesn't exist, the common culprits would be
You actually have a typo in the name of your table
You don't have permission to insert into the table. Note that if in your actual code, not everything is in the same schema, my guess would be that the user that owns the trigger has privileges to INSERT into the DP_REGISTRY table via a role rather than via a direct grant. Since priileges granted through a role are not available in a definer's rights stored procedure block, that would explain why you can do something at the command line but not in PL/SQL.

Date query in SQL2008

I have the following records depicting shifts in the Shifts table.
ID, Description, Start Time, End Time
1, Morning, 06:00, 13:59
2, Afternoon, 14:00, 21:59
3, Night, 22:00, 05:59
I now need to be able to get the shift relevant to a passed time but get stuck with getting the record for the night shift where the time starts before midnight and ends the following day.
What is the easiest way to query this table to get the correct shift based on a passed time?
TIA - Mike
The SQL 2008 time types might improve it slightly, but try this:
--Your Shift data as a temp table
declare #shifts table (ID int, Description varchar(10), [Start Time] smalldatetime, [End Time] smalldatetime)
insert into #shifts (ID, Description, [Start Time], [End Time])
select 1, 'Morning', '06:00', '13:59'
union all
select 2, 'Afternoon', '14:00', '21:59'
union all
select 3, 'Night', '22:00', '05:59'
-- Time to check
declare #timeToCheck smalldatetime
SET #timeToCheck='04:00'
-- The query to find the matching shift
select * from #shifts where
([Start Time]<[End Time] AND #timeToCheck>=[Start Time] AND #timeToCheck<=[End Time]) OR
([Start Time]>[End Time] AND (#timeToCheck>=[Start Time] OR #timeToCheck<=[End Time]))
Change the #timeToCheck to test it.
If you used a Datetime, it would include the date, you could then query the entire datetime and easily handle the result
you shouldn't need to store the end time, it's implied by the next start time.
if it makes it easier, you could have a second table with shift time ranges with a one-to-many relationship with shifts.
in the second table, add a fourth row with shift 3 ranging from 0 -> 5:59.
so table1 has 3 rows,
table2 has 4 like this:
shiftID shiftTime
3 00:00
1 06:00
2 14:00
3 22:00
if you want, you can add another column named isShiftStart marked true for times 06, 14, and 22, and false for time 00:00