Soring and counting records - tsql

I have a table with people with multiple entry and exit times during the day. This is done when they enter or exit certain location. How do I sort out records only to capture the last record. The Entry records. I am trying to sort out the persons still inside the location.
Name - Action - DateTime
John - Entry - 29-10-2019/09:00
John - Exit - 29-10-2019/10:00
John - Entry - 29-10-2019/11:00
Eva - Entry - 29-10-2019/09:00
Now how do I count only the people who entered and are still inside, not the one that exited the location. In the case above.
Would appreciate any help.
Thanks a lot,

select
name
,Action
,DateTime
from
(
select
name
,Action
,DateTime
,row_number() over (partition by name order by DateTime desc) rn
from <table>
) a
where rn=1
This catches the latest entry for each name.
If you want to see the ones still inside, just add
and Action='Entry'

Related

How to select max date value while selecting max value

I have the following sample from a table with students results with date for a school entry exam
First student passed exam - This is the most common record found for most students
Second student failed 1st time entry and passed second time based on the date
3rd student had a failed input entry and was corrected based on the Version
I need the results to like like the picture above, so we take into regard using the latest date and highest version!
My basic query thus far is
select studentid
,examdate --(Date)
,result -- (charvar)
from StudentEntryExam
How should I approach this issue?
demo:db<>fiddle
SELECT DISTINCT ON (studentid)
*
FROM mytable
ORDER BY studentid, examdate DESC, version DESC
DISTINCT ON returns the first record of an ordered group. In that case the groups are the studentids. You must find the correct order to set the required record first. So, you need to order by studentid, of course. Then you need the most recent examdate first, which can be achieved with DESC order. If there are two records on the same date, you need to order the highest version first as well using the DESC modifier, too.

How to Optimize PostgresqlSQL Query which contain INNER JOIN

I am trying to create a view which contain Suspicious order from a orders table.
The condition for the suspicious order is, every new order(in an interval), which have "New Customer" tag and used the discount codes(_sdc_sequence) from a table orders__discount_codes and either zip code or phone number of customer is matching in previous to that interval.
My attempt is
Created a view which contain all old orders(previous to the interval of 2 days) with "new customer tag"
CREATE OR REPLACE VIEW schema.old_orders_view AS
SELECT odr.id, odr.customer__id,odr.name, odr.billing_address__phone, odr.shipping_address__zip,odr.order_number, odr.updated_at
FROM schema.orders odr, schema.orders__discount_codes odc
WHERE odr._sdc_sequence=odc._sdc_sequence
AND
odr.updated_at<now() - interval '2 day'
AND
odr.tags LIKE'%New Customer%'
AND
odr.cancelled_at is null
AND
odr.confirmed ='t';
Created a view containing new orders(within the period 2 days)
CREATE OR REPLACE VIEW schema.new_orders_view AS
SELECT odr.id, odr.customer__id,odr.name, odr.billing_address__phone, odr.shipping_address__zip,odr.order_number, odr.updated_at
FROM schema.orders odr, schema.orders__discount_codes odc
WHERE odr._sdc_sequence=odc._sdc_sequence
AND
odr.updated_at>=now() - interval '2 day'
AND
odr.tags LIKE'%New Customer%'
AND
odr.cancelled_at is null
AND
odr. confirmed ='t';
later inner joined them
CREATE OR REPLACE VIEW schema.suspicious_orders_view AS
SELECT n_odr.customer__id new_customer__id,n_odr.name new_name,o_odr.customer__id old_customer__id,o_odr.name old_name,o_odr.updated_at old_updated_at,n_odr.updated_at new_updated_at, o_odr.id old_id, n_odr.id new_id
FROM
schema.new_orders_view n_odr, schema.old_orders_view o_odr
WHERE
o_odr.billing_address__phone=n_odr.billing_address__phone
OR
o_odr.shipping_address__zip=n_odr.shipping_address__zip;
What I need is the third View( suspicious_orders_view
).
Is there any way to optimize these queries? The table contain more than one 100K records. every day there is 50- 100 new records in new_orders_view
If the query is without two dummy view is more good (If it is not possible to optimize doing this also great).
I have used this in my application and tring to connect with google data studio
got error
ERROR:
Unable to Connect Host: An I/O error occurred while sending to the backed.
So, optimizing the query will be more appropriate.
I am using Postgresql 10.
Any help would be appreciated. Thank you in advance.

Grouping in a report

I am using t-sql.
I have 4 work trays and I would like a report that gives me the name of each work tray, plus the oldest item of post in it, plus a couple more fields. It needs to be limited to 4 rows - one for each work tray.
So at the moment I have this:
SELECT WorkTray, MIN(Date) AS [OldestDate], RefNo, NameofItem
FROM ...
GROUP BY WorkTray,RefNo, NameofItem
ORDER BY WorkTray,RefNo, NameofItem
However when I run this it gives me every item in each work tray, eg a report 100s of items long - I just want it to be limited to 4 rows of data, one for each work tray:
Work Tray Date RefNo NameofItem
A 1/2/15 25 Outstanding Bill
B 5/5/18 1000 Lost post
C 2/2/12 17 Misc
D 6/12/17 876 Misc
So I'm sure I'm going wrong somewhere with my GROUP BY - but I can't see where.
There is a trick for doing this that has been answered on stackoverflow before. Here it is adapted to your query:
SELECT *
FROM
(SELECT WorkTray, Date AS [OldestDate], RefNo, NameofItem, ROW_NUMBER() OVER (PARTITION BY WorkTray ORDER BY WorkTray, [Date]) AS rn
FROM MyTable
) GroupedByTray
WHERE rn = 1
The PARTITION BY tells it to count the rows for each type of tray, and the ORDER BY works similar to the normal ORDER BY clause. Assuming you have only 4 work trays (A - D), the "WHERE rn = 1" part will return only the first row for WorkTrays A - D.

SQL query with ranking order

All,
Need a help with one of the sql queries. I have a query which pulls up records on ranking order.
Select * from
(select count(*) cnt, customer_cd, smallint(Rank() Over(Order by count(8) Desc)) as rnk
from table.customer
Now, the result shows like,
Cnt Customer Cd
110 1- Retail
90 2-Human resources
20 3-Information Technology
11 Not Standard
I want to remove the description from it and will have only the Customer Codes such as 1,2,3,NS etc. Any help how to achieve this.
Thanks.
You could use LOCATE to find the position of the hyphen, assuming you always have a hyphen. Then, you could use SUBSTRING to get the portion of the string before the position found by LOCATE.
select substring(customer_cd,0,locate('-',customer_cd))
from table.customer
should show you what you will get.
You do seem to have some data (e.g. "Non Standard") that has no code at all. Such fields will come out as blank. If you want to replace that with some specific code, you can use a CASE...END expression.
select CASE when locate('-',customer_cd)==0 then ""
else substring(customer_cd,0, locate('-',customer_cd) ) END
from table.customer

SQL: Get first entry in aggregation function?

I have a simple table:
ID - JID - AMOUNT
1 - 1 - 100
2 - 2 - 50
3 - 2 - -25
4 - 3 - 100
5 - 3 - -50
I want to end up with:
JID - FIRSTBALANCE
1 - 100
2 - 50
3 - 100
Because Firebird is so insanely difficult when it comes to aggregation, this doesn't work:
SELECT jid, amount as firstBalance
FROM table
GROUP BY jid
How can I get it so it groups by JID, and automatically set the value of firstbalance to the first value in the table?
Depends on what do you mean with "automatically set the value of firstbalance to the first value in the table". From the example of the desired result you gave I thought you consider the row with lowest ID value for given JID group as "first" so
SELECT DISTINCT JID,
(SELECT amount FROM table s WHERE s.JID = o.JID ORDER BY s.ID ROWS 1)
FROM table o
should work.
Firebird does not contain a first() or a last() aggregate function. This has been requested and denied by the team due to which item would be chosen. You'd need to specify an order by clause for the items that get aggregated.
The answer you selected gets you the max(amount) not the first(amount). This is not what you asked for (though possibly it is what you wanted).
For future Googlers/Bingers here's how you get the first item. It's not a terrific solution, and it can be slow.
select distinct a.jid,
(select first 1 b.amount
from table b
where b.jid = a.jid
order by b.id) as amount
from table a
order by a.jid
It will retrieve the three JID fields and the first found amount as determined by ID order.
Don't hold your breath for this to get built into Firebird. When asked about a positional aggregate in the past, the response was:
"I have a great deal of trouble with that concept because position isn't a relational concept and the introduction of positional operators will signficantly inhibit efforts to improve performance by performing operations in parallel."
This is what I was looking for:
SELECT jid, max(amount) as firstBalance
FROM table
GROUP BY jid