How can I count rows in this sql statement? - sql

Could you help me by answering the following question?
How can I count rows in this sql statement?
SELECT `u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC

select count(*) from table or select count(column name) from table method returns the number of records
try
SELECT Count(*),
`u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC

Yes I know, but when I put count() in the statement I get 0 resulsts whilst without count() I get two in this case...
Can I use count() and HAVING in one sql statement?

You should be able to do it as a subquery SELECT COUNT(*) FROM (...) AS mysubquery. So maybe something like:
SELECT COUNT(*) FROM (
SELECT `u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC
) AS mysubquery

Related

Use of count in where statement sql

I have N transactions with camera_id = 6 and i want to sample every N // 100 transaction.
I have the following query:
SELECT t.id from (
SELECT id, camera_id, start_ts, ROW_NUMBER() OVER (ORDER BY start_ts) AS rownum
FROM transactions
WHERE camera_id = 6
) as t
where t.rownum % (N / 100) = 1
order by t.start_ts
How can i change it so i don't need additional query for determining N?
Untested
Does the following work for you - add a windowed count in addition to your Rownumber and use that:
SELECT t.id from (
SELECT id, camera_id, start_ts,
Row_Number() OVER (ORDER BY start_ts) AS rownum,
Count(*) over() Qty
FROM transactions
WHERE camera_id = 6
) as t
where t.rownum % (Qty / 100) = 1
order by t.start_ts

Combine two selects

I have a problem with two sql querys.
The one sql selects some ID's and the other one sets the id structur.
The problem is I can't get them both to work as one query.
The SQL which sets the structure:
select nstrid
from t_ousernstr
where kstrid = 116 And
Bis is null
Order by nstrid
The id's from that are like:
100
200
300
400
And the SQL which gets the user id's:
SELECT
T_OUSER.ID AS ID,
FROM
T_OUSER,
T_OUSERNSTR
WHERE
( T_OUSERNSTR.NSTRID = ANY(//here should be the id's from above))
(T_OUSERNSTR.VON is null or SYSDATE >=T_OUSERNSTR.VON) and
(T_OUSERNSTR.BIS is null) and
(T_OUSERNSTR.BEGINN IS NULL OR T_OUSERNSTR.BEGINN<= SYSDATE) and
(T_OUSERNSTR.ENDE is null or T_OUSERNSTR.ENDE> SYSDATE)
Order By T_OUSER.ID;
Use IN:
SELECT o.ID AS ID
FROM T_OUSER o
CROSS JOIN
T_OUSERNSTR n
WHERE n.NSTRID IN ( select nstrid
from t_ousernstr
where kstrid = 116
And Bis is null )
AND ( n.BIS IS NULL )
AND ( n.VON IS NULL OR SYSDATE >= n.VON )
AND ( n.BEGINN IS NULL OR SYSDATE >= n.BEGINN )
AND ( n.ENDE IS NULL OR SYSDATE < n.ENDE )
ORDER BY o.ID;
or EXISTS:
SELECT o.ID AS ID
FROM T_OUSER o
CROSS JOIN
T_OUSERNSTR n
WHERE EXISTS (
SELECT 1
FROM t_ousernstr x
WHERE x.kstrid = 116
AND x.Bis IS NULL
AND ( n.NSTRID = x.NSTRID OR ( n.NSTRID IS NULL AND x.NSTRID IS NULL ) )
)
AND ( n.BIS IS NULL )
AND ( n.VON IS NULL OR SYSDATE >= n.VON )
AND ( n.BEGINN IS NULL OR SYSDATE >= n.BEGINN )
AND ( n.ENDE IS NULL OR SYSDATE < n.ENDE )
ORDER BY o.ID;
or to remove the correlated sub-query you could use analytic functions:
SELECT o.ID AS ID
FROM T_OUSER o
CROSS JOIN
( SELECT n.*,
MAX( CASE WHEN kstrid = 116 THEN 1 ELSE 0 END )
OVER ( PARTITION BY bis, nstrid )
AS has_kstrid
FROM T_OUSERNSTR n
) n
WHERE n.has_kstrid = 1
AND ( n.BIS IS NULL )
AND ( n.VON IS NULL OR SYSDATE >= n.VON )
AND ( n.BEGINN IS NULL OR SYSDATE >= n.BEGINN )
AND ( n.ENDE IS NULL OR SYSDATE < n.ENDE )
ORDER BY o.ID;

what is the divisor is equal to zero in plsql?

SELECT pstartdate,
opbal,
joined,
resign,
( opbal + joined - resign ) clbal
,
( Round(( ( resign * 100 ) / ( opbal + joined ) ) / 100, 2) * 100
) attriation
FROM (SELECT pstartdate,
penddate,
Getopempbal(pstartdate) OpBal,
Getempjn(pstartdate, penddate) Joined,
Getempres(pstartdate, penddate) Resign
FROM (SELECT Add_months(:startdate, LEVEL - 1) pstartdate,
Add_months(:startdate, LEVEL) - 1 penddate
FROM dual
CONNECT BY LEVEL <= Months_between( :enddate, :startdate ) + 1))
ORDER BY To_number(1)
When i executed this query Error came
divisor is equal to zero.
i think error this place
(round(((resign*100)/(opbal+joined))/100,2)*100) attriation
I recommend that you use the nullif() function when doing division:
select . . .
( Round(( ( resign * 100 ) / nullif( opbal + joined, 0 ) ) / 100, 2) * 100
) attriation
This returns NULL if the denominator is zero.
SELECT pstartdate,
opbal,
joined,
resign,
(opbal+joined-resign) clbal,
round((**NULLIF**(resign,0) *100)/(opbal + joined)) ab
FROM
(SELECT pstartdate,
penddate,
getopempbal(pstartdate) opbal,
getempjn(pstartdate,penddate) joined,
getempres(pstartdate,penddate) resign
FROM
(SELECT add_months(:startdate, LEVEL-1) pstartdate,
add_months(:startdate, LEVEL)-1 penddate
FROM dual CONNECT BY LEVEL <= months_between(:enddate, :startdate) + 1))
ORDER BY to_number(1)

Postgres sub query returns 1 row, but exists returns false

I'm not sure how this is possible. This is an inner query for a NOT EXISTS test.
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
;
(1 row)
If I change the outer SELECT to count(subq.*) I get:
count
1
So far so good. But wrap the entire original query in SELECT EXISTS and:
exists
f
Why is this? I need this query to be wrapped in an outer query:
SELECT * FROM "clients" AS c WHERE status = 'Active' AND NOT EXISTS(
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = c.id
);
It is returning a row for the outer query even though the inner query returns 1 row.
Edit to add SELECT EXISTS:
SELECT EXISTS(
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
);
exists
f
(1 row)
And just for completeness:
SELECT 1 FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
?column?
(0 rows)

postgresql return 0 if returned value is null

I have a query that returns avg(price)
select avg(price)
from(
select *, cume_dist() OVER (ORDER BY price desc) from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
and price>( select avg(price)* 0.50
from(select *, cume_dist() OVER (ORDER BY price desc)
from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
)g
where cume_dist < 0.50
)
and price<( select avg(price)*2
from( select *, cume_dist() OVER (ORDER BY price desc)
from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
)d
where cume_dist < 0.50)
)s
having count(*) > 5
how to make it return 0 if no value is available?
use coalesce
COALESCE(value [, ...])
The COALESCE function returns the first of its arguments that is not null.
Null is returned only if all arguments are null. It is often
used to substitute a default value for null values when data is
retrieved for display.
Edit
Here's an example of COALESCE with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5
IMHO COALESCE should not be use with AVG because it modifies the value. NULL means unknown and nothing else. It's not like using it in SUM. In this example, if we replace AVG by SUM, the result is not distorted. Adding 0 to a sum doesn't hurt anyone but calculating an average with 0 for the unknown values, you don't get the real average.
In that case, I would add price IS NOT NULL in WHERE clause to avoid these unknown values.
(this answer was added to provide shorter and more generic examples to the question - without including all the case-specific details in the original question).
There are two distinct "problems" here, the first is if a table or subquery has no rows, the second is if there are NULL values in the query.
For all versions I've tested, postgres and mysql will ignore all NULL values when averaging, and it will return NULL if there is nothing to average over. This generally makes sense, as NULL is to be considered "unknown". If you want to override this you can use coalesce (as suggested by Luc M).
$ create table foo (bar int);
CREATE TABLE
$ select avg(bar) from foo;
avg
-----
(1 row)
$ select coalesce(avg(bar), 0) from foo;
coalesce
----------
0
(1 row)
$ insert into foo values (3);
INSERT 0 1
$ insert into foo values (9);
INSERT 0 1
$ insert into foo values (NULL);
INSERT 0 1
$ select coalesce(avg(bar), 0) from foo;
coalesce
--------------------
6.0000000000000000
(1 row)
of course, "from foo" can be replaced by "from (... any complicated logic here ...) as foo"
Now, should the NULL row in the table be counted as 0? Then coalesce has to be used inside the avg call.
$ select coalesce(avg(coalesce(bar, 0)), 0) from foo;
coalesce
--------------------
4.0000000000000000
(1 row)
I can think of 2 ways to achieve this:
IFNULL():
The IFNULL() function returns a specified value if the expression is NULL.If the expression is NOT NULL, this function returns the expression.
Syntax:
IFNULL(expression, alt_value)
Example of IFNULL() with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND IFNULL( price, 0 ) > ( SELECT AVG( IFNULL( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND IFNULL( price, 0 ) < ( SELECT AVG( IFNULL( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5
COALESCE()
The COALESCE() function returns the first non-null value in a list.
Syntax:
COALESCE(val1, val2, ...., val_n)
Example of COALESCE() with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5