PostgreSQL view embedded if-statements - postgresql

In my database, for stores that have no rating from Reseller Ratings, they still have an entry but have -1.0 instead of a number between 0.0 and 10.0. The following query results in -10.00 showing up in my view for those stores with -1.0. Instead, I would like either nothing or a - showing up in its place, but I'm not very comfortable with implementing embedded if-statements in my view. Here is my current view.
CREATE VIEW myview AS
SELECT co_url_name AS company_url, score_combined AS stella_score, trunc(score*10, 2) AS bizrate_score,
(SELECT trunc("lifetimeRating"*10, 2)) AS resellerRating_score
FROM ss_profile_co AS s LEFT OUTER JOIN "resellerRatings_ratings" AS r
ON s.id = r.company_id
LEFT OUTER JOIN (SELECT * FROM bizrate_bizrate_ratings WHERE score_name = 'Overall rating') AS b
ON s.id = b.fk_co_id
ORDER BY co_url_name ASC;
The line (SELECT trunc("lifetimeRating"*10, 2)) AS resellerRating_score is the one that returns the negative numbers (or, for valid entries, will return a score between 0.00 and 100.00).
Obviously, I could simply remove these entries from the database that result in this, but it's half a learning experience and half out of my hands to do so anyways.
I appreciate the help!
EDIT: Attempted an embedded if but not surprisingly got an error.
IF (SELECT trunc("lifetimeRating"*10, 2)) = -10.00 THEN NULL ELSE (SELECT trunc("lifetimeRating"*10, 2)) AS resellerRating_score
EDIT2: Figured it out. Line in question is as follows:
(SELECT trunc("lifetimeRating"*10, 2) WHERE trunc("lifetimeRating"*10, 2) > 0) AS resellerrating_score
/foreveralone

Could look like this:
CREATE VIEW myview AS
SELECT co_url_name AS company_url
,score_combined AS stella_score
,trunc(score * 10, 2) AS bizrate_score
,CASE WHEN "lifetimeRating" < 0
THEN NULL
ELSE trunc("lifetimeRating" * 10, 2)
END AS resellerRating_score
FROM ss_profile_co s
LEFT JOIN "resellerRatings_ratings" r ON r.company_id = s.id
LEFT JOIN bizrate_bizrate_ratings b ON b.score_name = 'Overall rating'
AND b.fk_co_id = s.id
ORDER BY co_url_name;
Major points
Concerning your core question: the sub-select without a FROM clause serves no purpose. I simplified that and use a CASE statement instead.
I also simplified your LEFT JOIN to bizrate_bizrate_ratings. No sub-select necessary either. I pulled the WHERE clause up into the JOIN condition. Simpler and faster.
I would advise not to use mixed case identifiers, so you never have to use double quotes. (This probably makes #Daniels comment invalid, because lifetimerating != "lifetimeRating"

Related

How to perform WHERE in with multiple columns in postgres

I wants to do something like this,
SELECT * FROM product p
JOIN product_version pv ON p.id = pv.product_id
where (p.code, pv.product_version) in (("FF6",1), ("FF12", 1));
But this is giving error at in clause.
Can someone provide the correct syntax.
You are not providing any information about the actual error neither about column types.
But, by the way, it really looks like that those double quotes are wrong because in Postgres strings are quoted using simple quotes ('), not double (").
Try:
SELECT *
FROM product p
JOIN product_version pv ON (p.id = pv.product_id)
where
(p.code, pv.product_version) in (('FF6',1), ('FF12', 1))
;
Despite that, your query looks syntactically "correct" unless some kind of type mismatching we cannot foresee without more information.
You probably can't go with IN, depending on your goal you need to do something like:
where (p.code = "FF6" and pv.product_version = 1) or
(p.code = "FF12" and pv.product_version = 1)
or, if the logic above was not what you meant, maybe:
where p.code IN ("FF6", "FF12} AND pv.product_version IN (1)
or
where p.code IN ("FF6", "FF12} OR pv.product_version IN (1)
This code should work for you
SELECT * FROM product p
JOIN product_version pv ON p.id = pv.product_id
where p.code in("FF6","FF12") and pv.product_version = 1

Optimizing Postgres query with timestamp filter

I have a query:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND (sent_email_v2s.sent >= '2016-03-18')
AND "users"."team_id" = 1
When I run EXPLAIN ANALYZE on it, I get:
Then, if I change that to the following (Just removing the (sent_email_v2s.sent >= '2016-03-18')) as follows:
SELECT DISTINCT ON (analytics_staging_v2s.event_type, sent_email_v2s.recipient, sent_email_v2s.sent) sent_email_v2s.id, sent_email_v2s.user_id, analytics_staging_v2s.event_type, sent_email_v2s.campaign_id, sent_email_v2s.recipient, sent_email_v2s.sent, sent_email_v2s.stage, sent_email_v2s.sequence_id, people.role, people.company, people.first_name, people.last_name, sequences.name as sequence_name
FROM "sent_email_v2s"
LEFT JOIN analytics_staging_v2s ON sent_email_v2s.id = analytics_staging_v2s.sent_email_v2_id
JOIN people ON sent_email_v2s.person_id = people.id
JOIN sequences on sent_email_v2s.sequence_id = sequences.id
JOIN users ON sent_email_v2s.user_id = users.id
WHERE "sent_email_v2s"."status" = 1
AND "people"."person_type" = 0
AND (sent_email_v2s.sequence_id = 1888) AND "users"."team_id" = 1
when I run EXPLAIN ANALYZE on this query, the results are:
EDIT:
The results above from today are about as I expected. When I ran this last night, however, the difference created by including the timestamp filter was about 100x slower (0.5s -> 59s). The EXPLAIN ANALYZE from last night showed all of the time increase to be attributed to the first unique/sort operation in the query plan above.
Could there be some kind of caching issue here? I am worried now that there might be something else going on (transiently) that might make this query take 100x longer since it happened at least once.
Any thoughts are appreciated!

Why is this field not showing up in the results?

When I run the selects below, I do not get Field3 in the result set, why?
Select
a.Field1,
a.Field2,
a.Field3,
sum(IsNull(a.Field4, 0)) AS SomeAlias1,
a.SomeField5,
a.SomeField6,
a.SomeField7
From SomeTable a
INNER JOIN SomeView1 v on v.au = a.au
inner join (select Username, House from Users userBuildings where UserName = #UserName) as userHouses on userHouses.au = a.au
WHERE
(((where claus logic here....
Group BY a.Field1,
a.Field2,
a.SomeAlias1,
a.Field3,
a.Field4,
a.Field5,
a.Field6,
a.Fielf7
)
Select
transBudget.Field1,
transBudget.Field2,
transDiscount.Field4,
... some other fields...
IsNull(transDiscount.Actual, 0) - IsNull(transBudget.Actual, 0) AS Variance
from (Select * from Transactdions Where TransDesc = 'Budget') AS transBudget
FULL OUTER JOIN
(Select * from Transactions Where TransDesc = 'Discount') AS transDiscount
ON transBudget.Market = transDiscount.Market AND transBudget.SubMarket = transDiscount.SubMarket
I see every field except Field3 for some reason and it's beyond me how the heck this can happen.
In the second part of your query, you are missing field 3.
Select
transBudget.Field1,
transBudget.Field2,
transDiscount.Field4,
... some other fields...
IsNull(transDiscount.Actual, 0)
You appear to have two separate SQL queries there. The first one contains Field3, but the second one does not.

TSQL CTE Error: Incorrect syntax near ')'

I am developing a TSQL stored proc using SSMS 2008 and am receiving the above error while generating a CTE. I want to add logic to this SP to return every day, not just the days with data. How do I do this? Here is my SP so far:
ALTER Proc [dbo].[rpt_rd_CensusWithChart]
#program uniqueidentifier = NULL,
#office uniqueidentifier = NULL
AS
DECLARE #a_date datetime
SET #a_date = case when MONTH(GETDATE()) >= 7 THEN '7/1/' + CAST(YEAR(GETDATE()) AS VARCHAR(30))
ELSE '7/1/' + CAST(YEAR(GETDATE())-1 AS VARCHAR(30)) END
if exists (
select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#ENROLLEES')
) DROP TABLE #ENROLLEES;
if exists (
select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#DISCHARGES')
) DROP TABLE #DISCHARGES;
declare #sum_enrollment int
set #sum_enrollment =
(select sum(1)
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id
where
(#office is NULL OR A.group_profile_id = #office)
AND (#program is NULL OR A.program_info_id = #program)
and (C.pe_end_date IS NULL OR C.pe_end_date > #a_date)
AND C.pe_start_date IS NOT NULL and C.pe_start_date < #a_date)
select
A.program_info_id as [Program code],
A.[program_name],
A.profile_name as Facility,
A.group_profile_id as Facility_code,
A.people_id,
1 as enrollment_id,
C.pe_start_date,
C.pe_end_date,
LEFT(datename(month,(C.pe_start_date)),3) as a_month,
day(C.pe_start_date) as a_day,
#sum_enrollment as sum_enrollment
into #ENROLLEES
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id
where
(#office is NULL OR A.group_profile_id = #office)
AND (#program is NULL OR A.program_info_id = #program)
and (C.pe_end_date IS NULL OR C.pe_end_date > #a_date)
AND C.pe_start_date IS NOT NULL and C.pe_start_date >= #a_date
;WITH #ENROLLEES AS (
SELECT '7/1/11' AS dt
UNION ALL
SELECT DATEADD(d, 1, pe_start_date) as dt
FROM #ENROLLEES s
WHERE DATEADD(d, 1, pe_start_date) <= '12/1/11')
The most obvious issue (and probably the one that causes the error message too) is the absence of the actual statement to which the last CTE is supposed to pertain. I presume it should be a SELECT statement, one that would combine the result set of the CTE with the data from the #ENROLLEES table.
And that's where another issue emerges.
You see, apart from the fact that a name that starts with a single # is hardly advisable for anything that is not a local temporary table (a CTE is not a table indeed), you've also chosen for your CTE a particular name that already belongs to an existing table (more precisely, to the already mentioned #ENROLLEES temporary table), and the one you are going to pull data from too. You should definitely not use an existing table's name for a CTE, or you will not be able to join it with the CTE due to the name conflict.
It also appears that, based on its code, the last CTE represents an unfinished implementation of the logic you say you want to add to the SP. I can suggest some idea, but before I go on I'd like you to realise that there are actually two different requests in your post. One is about finding the cause of the error message, the other is about code for a new logic. Generally you are probably better off separating such requests into distinct questions, and so you might be in this case as well.
Anyway, here's my suggestion:
build a complete list of dates you want to be accounted for in the result set (that's what the CTE will be used for);
left-join that list with the #ENROLLEES table to pick data for the existing dates and some defaults or NULLs for the non-existing ones.
It might be implemented like this:
… /* all your code up until the last WITH */
;
WITH cte AS (
SELECT CAST('7/1/11' AS date) AS dt
UNION ALL
SELECT DATEADD(d, 1, dt) as dt
FROM cte
WHERE dt < '12/1/11'
)
SELECT
cte.dt,
tmp.[Program code],
tmp.[program_name],
… /* other columns as necessary; you might also consider
enveloping some or all of the "tmp" columns in ISNULLs,
like in
ISNULL(tmp.[Program code], '(none)') AS [Program code]
to provide default values for absent data */
FROM cte
LEFT JOIN #ENROLLEES tmp ON cte.dt = tmp.pe_start_date
;

How to determine the size of a Full-Text Index on SQL Server 2008 R2?

I have a SQL 2008 R2 database with some tables on it having some of those tables a Full-Text Index defined. I'd like to know how to determine the size of the index of a specific table, in order to control and predict it's growth.
Is there a way of doing this?
The catalog view sys.fulltext_index_fragments keeps track of the size of each fragment, regardless of catalog, so you can take the SUM this way. This assumes the limitation of one full-text index per table is going to remain the case. The following query will get you the size of each full-text index in the database, again regardless of catalog, but you could use the WHERE clause if you only care about a specific table.
SELECT
[table] = OBJECT_SCHEMA_NAME(table_id) + '.' + OBJECT_NAME(table_id),
size_in_KB = CONVERT(DECIMAL(12,2), SUM(data_size/1024.0))
FROM sys.fulltext_index_fragments
-- WHERE table_id = OBJECT_ID('dbo.specific_table_name')
GROUP BY table_id;
Also note that if the count of fragments is high you might consider a reorganize.
If you are after a specific Catalogue
Use SSMS
- Clik on [Database] and expand the objects
- Click on [Storage]
- Right Click on {Specific Catalogue}
- Choose Propertie and click.
IN General TAB.. You will find the Catalogue Size = 'nn'
I use something similar to this (which will also calculate the size of XML-indexes, ... if present)
SELECT S.name,
SO.name,
SIT.internal_type_desc,
rows = CASE WHEN GROUPING(SIT.internal_type_desc) = 0 THEN SUM(SP.rows)
END,
TotalSpaceGB = SUM(SAU.total_pages) * 8 / 1048576.0,
UsedSpaceGB = SUM(SAU.used_pages) * 8 / 1048576.0,
UnusedSpaceGB = SUM(SAU.total_pages - SAU.used_pages) * 8 / 1048576.0,
TotalSpaceKB = SUM(SAU.total_pages) * 8,
UsedSpaceKB = SUM(SAU.used_pages) * 8,
UnusedSpaceKB = SUM(SAU.total_pages - SAU.used_pages) * 8
FROM sys.objects SO
INNER JOIN sys.schemas S ON S.schema_id = SO.schema_id
INNER JOIN sys.internal_tables SIT ON SIT.parent_object_id = SO.object_id
INNER JOIN sys.partitions SP ON SP.object_id = SIT.object_id
INNER JOIN sys.allocation_units SAU ON (SAU.type IN (1, 3)
AND SAU.container_id = SP.hobt_id)
OR (SAU.type = 2
AND SAU.container_id = SP.partition_id)
WHERE S.name = 'schema'
--AND SO.name IN ('TableName')
GROUP BY GROUPING SETS(
(S.name,
SO.name,
SIT.internal_type_desc),
(S.name, SO.name), (S.name), ())
ORDER BY S.name,
SO.name,
SIT.internal_type_desc;
This will generally give numbers higher than sys.fulltext_index_fragments, but when combined with the sys.partitions of the table, it will add up to the numbers returned from EXEC sys.sp_spaceused #objname = N'schema.TableName';.
Tested with SQL Server 2016, but documentation says it should be present since 2008.