A Way To Count Result Based on Date - sql-server

SELECT
a.OrderSuffix AS 'OrderSuffix',
COUNT(1) AS 'CountNew'
FROM
dbo.Orders AS a,
dbo.OrderStatus AS b
WHERE
b.Status = 'Finished' AND
a.OrderSuffix IN ('ABC', 'DEF', 'HIJ')
GROUP BY
a.OrderSuffix
For this query above, I can get all total rows count for each order suffix. Is there a way to include a date as well?
E.g. I want to count all rows of 'ABC' whose dateField is greater than specifiedDate.

If you want to filter rows before you aggregate, you can just put it in your WHERE clause.
If you want the comparison to be based on the aggregate (e.g. groups with, say, a max dateField greater than some value) you can use the HAVING clause.

Related

SQL Server : Join If Between

I have 2 tables:
Query1: contains 3 columns, Due_Date, Received_Date, Diff
where Diff is the difference in the two dates in days
QueryHol with 2 columns, Date, Count
This has a list of dates and the count is set to 1 for everything. All these dates represent public holidays.
I want to be able to get the sum of QueryHol["Count"] if QueryHol["Date"] is between Query1["Due_Date"] and Query1["Received_Date"]
Result Wanted: a column joined onto Query1 to state how many public holidays fell into the date range so they can be subtracted from the Query1["Diff"] column to give a reflection of working days.
Because the 01-01-19 is a bank holiday i would want to minus that from the Diff to end up with results like below
Let me know if you require any more info.
Here's an option:
SELECT query1.due_date
, query1.received_date
, query1.diff
, queryhol.count
, COALESCE(query1.diff - queryhol.count, query1.diff) as DiffCount
FROM Query1
OUTER APPLY(
SELECT COUNT(*) AS count
FROM QueryHol
WHERE QueryHol.Date <= Query1.Received_Date
AND QueryHol.Date >= Query1.Due_Date
) AS queryhol
You may need to play around with the join condition - as it is assumes that the Received_Date is always later than the Due_Date which there is not enough data to know all of the use cases.
If I understand your problem, I think this is a possible solution:
select due_date,
receive_date,
diff,
(select sum(table2.count)
from table2
where table2.due_date between table1.due_date and table1.due_date) sum_holi,
table1.diff - (select sum(table2.count)
from table2
where table2.date between table1.due_date and table2.due_date) diff_holi
from table1
where [...] --here your conditions over table1.

logic behind using temp table instead of group by in sub query

In my table country :
name|gdp|city
-------------
S.A |60 |amr
S.A |60 |amb
US |200|ken
US |70 |mas
aus |80 |po
aus |90 |tr
I want to get the country whose gdp is lower than 100.
when I use (2) it doesnt work and gives error because it returns multiple values which have to be compared to where condition.when I use (1) it works even though the sub query still gives back multiple values which are compared to 100.
What is the logic behind it please explain because I am new to sql. how is subquery in (1) different from (2)
(1)
SELECT DISTINCT
name
FROM country a
WHERE 100 > (SELECT SUM(gdp)FROM country b WHERE a.name = b.name);
(2)
SELECT DISTINCT
name
FROM country a
WHERE 100 > (SELECT SUM(gdp)FROM country b GROUP BY name);
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
When you are using (2): You are getting multiple values in the Subquery, as you are not having WHERE condition. You are getting multiple countries and corresponding sum. So, you are getting error.
When you are using (1): You are getting single value in Subquery, as you are getting single gdp as you are applying filter at country level. For each country, you are getting single sum only. So, you are not getting error.
The sub-query in query number 1 does not return multiple values. What you have there is called a "correlated sub-query". The sub-query has a WHERE clause that relates the results of the sub-query (the "inner" query) to the main query (the "outer" query). It's this bit WHERE a.name = b.name. Functionally, that query is run on a row-by-row basis where the name values match, and the sub-query only returns the single result for that name value. You'll notice that you can't run the sub-query by itself, because it needs to get the name value from the outer query in order to work.
In query number 2, if you run the sub-query by itself, it will return a list of summed gdp values. One column, with several rows. The GROUP BY clause is telling the query to SUM the results by name, but the result set doesn't contain the name value, so it's just a list of numbers. The outer query has no way of knowing which row of that result set you want to compare to 100, and so it throws the error that you received.
Seems like you're after a HAVING here:
CREATE TABLE dbo.Country ([name] varchar(3),
gdp smallint,
city varchar(3));
INSERT INTO dbo.Country (name,
gdp,
city)
VALUES ('S.A', 60, 'amr'),
('S.A', 60, 'amb'),
('US ', 200, 'ken'),
('US ', 70, 'mas'),
('aus', 80, 'po '),
('aus', 90, 'tr ');
GO
SELECT C.name
FROM dbo.Country C
GROUP BY C.name
HAVING SUM(C.gdp) < 100
GO
DROP TABLE dbo.Country;
As you want rows where "the country gdp is lower than 100" this returns no rows, as there are no countries where the SUM of the gdp is lower than 100. (S.A has 120, US has 270, and aus has 170).
If the gbp of a Country (not the City) is worked out differently, you may need to use a different aggregate function (AVG, MAX?) or a completely different method. if so, you should explain which rows you are expecting in your question and why.

BigQuery standard SQL: how to group by an ARRAY field

My table has two columns, id and a. Column id contains a number, column a contains an array of strings. I want to count the number of unique id for a given array, equality between arrays being defined as "same size, same string for each index".
When using GROUP BY a, I get Grouping by expressions of type ARRAY is not allowed. I can use something like GROUP BY ARRAY_TO_STRING(a, ","), but then the two arrays ["a,b"] and ["a","b"] are grouped together, and I lose the "real" value of my array (so if I want to use it later in another query, I have to split the string).
The values in this field array come from the user, so I can't assume that some character is simply never going to be there (and use it as a separator).
Instead of GROUP BY ARRAY_TO_STRING(a, ",") use GROUP BY TO_JSON_STRING(a)
so your query will look like below
#standardsql
SELECT
TO_JSON_STRING(a) arr,
COUNT(DISTINCT id) cnt
FROM `project.dataset.table`
GROUP BY arr
You can test it with dummy data like below
#standardsql
WITH `project.dataset.table` AS (
SELECT 1 id, ["a,b", "c"] a UNION ALL
SELECT 1, ["a","b,c"]
)
SELECT
TO_JSON_STRING(a) arr,
COUNT(DISTINCT id) cnt
FROM `project.dataset.table`
GROUP BY arr
with result as
Row arr cnt
1 ["a,b","c"] 1
2 ["a","b,c"] 1
Update based on #Ted's comment
#standardsql
SELECT
ANY_VALUE(a) a,
COUNT(DISTINCT id) cnt
FROM `project.dataset.table`
GROUP BY TO_JSON_STRING(a)
Alternatively, you can use another separator than comma
ARRAY_TO_STRING(a,"|")

How to select Second Last Row in mySql?

I want to retrieve the 2nd last row result and I have seen this question:
How can I retrieve second last row?
but it uses order by which in my case does not work because the Emp_Number Column contains number of rows and date time stamp that mixes data if I use order by .
The rows 22 and 23 contain the total number of rows (excluding row 21 and 22) and the time and day it got entered respectively.
I used this query which returns the required result 21 but if this number increases it will cause an error.
SELECT TOP 1 *
FROM(
SELECT TOP 2 *
FROM DAT_History
ORDER BY Emp_Number ASC
) t
ORDER BY Emp_Number desc
Is there any way to get the 2nd last row value without using the Order By function?
There is no guarantee that the count will be returned in the one-but-last row, as there is no definite order defined. Even if those records were written in the correct order, the engine is free to return the records in any order, unless you specify an order by clause. But apparently you don't have a column to put in that clause to reproduce the intended order.
I propose these solutions:
1. Return the minimum of those values that represent positive integers
select min(Emp_Number * 1)
from DAT_history
where Emp_Number not regexp '[^0-9]'
See SQL Fiddle
This will obviously fail when the count is larger then the smallest employee number. But seeing the sample data, that would represent a number of records that is maybe not expected...
2. Count the records, ignoring the 2 aggregated records
select count(*)-2
from DAT_history
See SQL Fiddle
3. Relying on correct order without order by
As explained at the start, you cannot rely on the order, but if for some reason you still want to rely on this, you can use a variable to number the rows in a sub query, and then pick out the one that has been attributed the one-but-last number:
select Emp_Number * 1
from (select Emp_Number,
#rn := #rn + 1 rn
from DAT_history,
(select #rn := 0) init
) numbered
where rn = #rn - 1
See SQL Fiddle
The * 1 is added to convert the text to a number data type.
This is not a perfect solution. I am making some assumptions for this. Check if this could work for you.
;WITH cte
AS (SELECT emp_number,
Row_number()
OVER (
ORDER BY emp_number ASC) AS rn
FROM dat_history
WHERE Isdate(emp_number) = 0) --Omit date entries
SELECT emp_number
FROM cte
WHERE rn = 1 -- select the minimum entry, assuming it would be the count and assuming count might not exceed the emp number range of 9888000

select max and min from multiple tables

I am using SQL Server 2012. I have two tables that contain dates. I want to query the max and min dates from both tables. I know the line below will give me the max and min dates for one table.
select max(dtTime), min(dtTime) from tableOne
What I want to do is get the min of the two max dates from table one and two & the max of the two min dates from the table. Please see the example below.
TableOne TableTwo
Max Date 6-June-2000 23-June-2002
Min Date 10-Jan-1980 15-Feb-1982
Result I would like returned,
Max Date = 6-June-2000
Min Date = 15-Feb-1982
You can use UNION, and then select minimum from max values and max from minimum values:
SELECT min(mx), max(mn)
FROM (
SELECT max(dtTime) AS `mx`, min(dtTime) AS `mn` FROM tableOne
UNION
SELECT max(dtTime) AS `mx`, min(dtTime) AS `mn` FROM tablTow
) AS t1
select max(t1.dtTime), min(t2.dtTime) from tableOne as t1, tableTwo as t2

Resources