SQL Query for Count value from the latest date - sql

I need to have a query that returns the ff:
Count from the latest Date in each Name
If the value of Count from the latest Date is -1 then it will return the count of the Date before the latest Date
If the value of Count from the latest Date is -1 and the other Date is -1. Then return 0
If the value of Count from the latest Date is -1 and no other Date of that Name. Then return 0
Example Table:
ID Name Date Count
1 Adj 09/29/2012 2
2 Adj 09/30/2012 4
3 Ped 09/29/2012 -1
4 Ped 09/30/2012 5
5 Mel 09/29/2012 3
6 Mel 09/30/2012 -1
7 Rod 09/30/2012 7
8 Ney 09/30/2012 -1
9 Jin 09/29/2012 -1
10 Jin 09/30/2012 -1
Desired Output:
Name Count
Adj 4
Ped 5
Mel 3
Rod 7
Ney 0
Jin 0
I am very confused on how to approach this in SQL since I only knew simple query.
Any idea on how to make a query for this? Thanks.
Btw, I'm sorry I forgot to include this. I am using SQL Server 2000.

Try this
SQL FIDDLE EXAMPLE
select A.name, isnull(T.[Count], 0) as [Count]
from (select distinct T.name from table1 as T) as A
outer apply
(
select top 1 T.[Count]
from table1 as T
where T.name = A.name and T.[Count] <> -1
order by T.[date] desc
) as T
order by A.name asc
UPDATE: for SQL 2000 you can use query like this
SQL FIDDLE EXAMPLE for SQL 2000
select A.name, isnull(T1.[Count], 0) as [Count]
from
(
select T.name, max(case when T.[Count] <> -1 then T.[date] else null end) as [date]
from table1 as T
group by T.name
) as A
left outer join table1 as T1 on T1.name = A.name and T1.[date] = A.[date]
but it relies on suggestion that you have unique constraint on name, [date] columns

an other one
Select * from
(
Select Test.name,[Count]
from TEST
Join(
Select name, MAX(Date) as Date from TEST
where [Count]<>-1
Group by Name) a
on a.Name=test.Name and a.Date=Test.Date
UNION
Select Distinct name,0 from test o where not Exists(Select * from test where name=o.Name and [count]<>-1)
) res
order by Name

Related

How to merge two query results joining same date

let's say there's a table have data like below
id
status
date
1
4
2022-05
2
3
2022-06
I want find count of id of each month by their status. Something like this below
date
count(status1) = 4
count(status2) =3
2022-05
1
null
2022-06
null
1
I tried doing
-- select distinct (not working)
select date, status1, status2 from
(select date, count(id) as "status1" from myTable
where status = 4 group by date) as myTable1
join
(select date, count(id) as "status2" from myTable
where status = 3 group by date) as myTable2
on myTable1.date = myTable2.date;
-- group by (not working)
but it does duplicate the data needed.
and I am using SQL Server.
select d.date,
sum
(
case
when d.status=4 then 1
else 0
end
)count_status_4,
sum
(
case
when d.status=5 then 1
else 0
end
)count_status_5
from your_table as d
group by d.date

Update table column based on CTE result

I have the code shown below, and I want to update my original table to reflect the results of this query. I want each record's Route_type column to update with the corresponding value from the Route_type column in the query based on the code associated with each record. For instance, all records with code=1 should have Route_Type updated to "Other" based on the query.
With Route_Number_CTE (Code,Year_and_Week, Route_Count) As
(
Select
Code, Year_and_Week, Count(Route) AS Route_Count
From
Deliveries
Group by
Code, Year_and_Week
)
select
d.Code,
min(r.Route_Count) As Min_Count,
max(r.Route_Count) As Max_Count,
(case
When max(r.Route_Count) = 1 then 'One'
When max(r.Route_Count) <= 3 AND min(r.Route_Count) > 1 then 'Three or less'
When min(r.Route_Count) > 4 then 'Four or More'
Else 'Other'
End) As Route_Type
From
Deliveries as d
inner join
Route_Number_CTE as r on d.Code = r.Code
Group By
d.Code;
Query results:
Code Min_Count Max_Count Route_Type
----------------------------------------
1 1 4 Other
2 1 2 Three or less
3 3 3 Three or less
Deliveries:
Code Route Route_Type
-------------------------
1 A
1 C
1 D
2 A
2 C
2 B
3 A
3 C
3 D
I think that you could use window functions and an updatable cte. This is simpler, and should be more efficient as it avoids the need for aggregation and joins:
with cte as (
select route_type, max(cnt) over(partition by code) max_cnt
from (
select d.*, count(*) over(partition by code, year_and_week) cnt
from deliveries d
) d
)
update cte
set route_type = case
when max_cnt = 1 then 'One'
when max_cnt <= 3 then 'Three or less'
when max_cnt > 4 then 'Four or more'
end
I figured it out by just creating a second CTE from the second Select statement and using an update query with the result.

Running total (COUNT) SQL Server

I currently have this result
ID Code
1 AAA12
2 F5
3 GOFK568
4 G77
5 JLKJ4
6 FOG0
Now what i want to do is to create a third column that keeps a running total for codes that are above 4 in length.
Now, i have this code that gives me the sum of the code with above 4 in length.
SELECT * ,
SUM(CASE WHEN LENGTH(CODE) > 4 THEN 1 ELSE 0 END) AS [Count]
FROM Table1;
But this gives me this result
ID Code Count
1 AAA12 3
I am looking for a result like this
ID Code Running_Total
1 AAA12 1
2 F5 1
3 GOFK568 2
4 G77 2
5 JLKJ4 3
6 FOG0 3
I was working on something similar to this
SELECT * ,
CASE WHEN LENGTH(CODE) > 4 THEN (SUM(Code) OVER (PARTITION BY ID)) ELSE END
AS [Count]
FROM Table1;
But it still doesn't give me a running total.
I have an SQL Fiddle page
http://sqlfiddle.com/#!9/2746c/18
Any help would be great
Put the case in the sum:
SELECT Table1.* ,
SUM(case when len(Code) > 4 then 1 else 0 end) OVER (order BY ID) as counted
FROM Table1;
In Sql Server 2012+ you can use Sum() Over(Order by) function
SELECT Sum(CASE WHEN Len(code) > 4 THEN 1 ELSE 0 END)
OVER(ORDER BY id)
FROM Yourtable
for older versions
SELECT *
FROM Yourtable a
CROSS apply (SELECT Count(*)
FROM Yourtable b
WHERE a.ID >= b.ID
AND Len(code) > 4) cs (runn)
ANSI SQL method
SELECT ID,Code,
(SELECT count(*)
FROM Yourtable b
WHERE a.ID >= b.ID and char_length(code) > 4) AS runn
FROM Yourtable a
There are some good and efficient answers here.
But in case you want to try different approach then try following query:
SELECT
t1.*,
(Select sum(r.cnt) from
(SELECT COUNT(t2.code) as cnt FROM table1 AS t2
WHERE t2.Id <= t1.Id
group by t2.code
having len(t11.code) > 4) r
) AS Count
FROM table1 AS t1;
Here is the DEMO
Hope it helps!

SQL query count (recursive)

I have the following table on my database which contains some transactions for which I need to calc points and rewards.
Every time a TxType A occurs I should record 10 points.
Then I have to subtract from these points the value of the PP column every time a TxType B occurs.
When the calculation goes to zero a reward is reached.
ID TxType PP
1 A 0
2 B 2
3 B 1
4 B 1
5 B 1
6 B 3
7 B 1
8 B 1
9 A 0
10 B 4
11 B 3
12 B 2
13 B 1
14 A 0
15 B 2
I have created the sql query to calc points as follow
SELECT SUM(
CASE
WHEN TxType = 'A' THEN 10
WHEN TxType = 'B' THEN (PP * -1)
END)
FROM myTable
This query return the value of 8, which is exactly the number of points based on the sample data.
How do I calculate the rewards occurred (2 in the given example)?
thanks for helping
One way to do the calculation (in SQL Server 2008) using a correlated subquery:
select t.*,
(select sum(case when TxType = 'A' then 10
when TxType = 'B' then PP * -1
end)
from mytable t2
where t2.id <= t.id
) as TheSum
from mytable t;
You can then apply the logic of what happens when the value is 0. In SQL Server 2012, you could just use a cumulative sum.
To complete Gordon Linoff's the answer, you just need to count the records where TheSum is 0 to get how many rewards occurred:
SELECT COUNT(1)
FROM (
SELECT ID,
TxType,
PP,
( SELECT SUM(CASE TxType WHEN 'A' THEN 10 WHEN 'B' THEN -PP END)
FROM #myTable t2
WHERE t2.id <= t1.id
) AS TheSum
FROM #myTable t1
) Result
WHERE TheSum = 0

SQL - categorize rows

Below is the result set I am working with. What I would like is an additional column that identifies a X number of rows as the same. In my result set, rows 1-4 are the same (would like to mark as 1), rows 5-9 are the same (mark as 2); row 10 (mark as 3)
How is this possible using just SQL? I can't seem to do this using rank or dense_rank functions.
ranking diff bool
-------------------- ----------- -----------
1 0 0
2 0 0
3 0 0
4 0 0
5 54 1
6 0 0
7 0 0
8 0 0
9 0 0
10 62 1
In general case you can do something like this:
select
t.ranking, t.[diff], t.[bool],
dense_rank() over(order by c.cnt) as rnk
from Table1 as t
outer apply (
select count(*) as cnt
from Table1 as t2
where t2.ranking <= t.ranking and t2.[bool] = 1
) as c
In your case you can do it even without dense_rank():
select
t.ranking, t.[diff], t.[bool],
c.cnt + 1 as rnk
from Table1 as t
outer apply (
select count(*) as cnt
from Table1 as t2
where t2.ranking <= t.ranking and t2.[bool] = 1
) as c;
Unfortunately, in SQL Server 2008 you cannot do running total with window function, in SQL Server 2012 it'd be possible to do it with sum([bool]) over(order by ranking).
If you have really big number of rows and your ranking column is unique/primary key, you can use recursive cte approach - like one in this answer, it's fastest one in SQL Server 2008 R2:
;with cte as
(
select t.ranking, t.[diff], t.[bool], t.[bool] as rnk
from Table1 as t
where t.ranking = 1
union all
select t.ranking, t.[diff], t.[bool], t.[bool] + c.rnk as rnk
from cte as c
inner join Table1 as t on t.ranking = c.ranking + 1
)
select t.ranking, t.[diff], t.[bool], 1 + t.rnk
from cte as t
option (maxrecursion 0)
sql fiddle demo