I have reviewed the other replies to this problem, but cannot find the appropriate response to my situation. I am trying to divide "actual hours" by "estimated hours". However, estimated hours can be null (no entry) or zero. Actual hours can be zero. So when I get to the division statement, I can't have estimated hours as null or actual hours as zero. My "coalesce" statements don't appear to be helping. Any advice would be helpful.
SELECT PUV.ProjectName, PUV.[Project ID], PUV.[Project Director], PUV.[Project Owner (Manager)], PUV.[Project Type1], **COALESCE( PUV.[Estimated Hours], 0 ) AS EstHours
,PUV.ProjectStatusDate, PUV.ProjectStartDate, PUV.ProjectBaseline0StartDate, PUV.ProjectActualStartDate, PUV.ProjectStartVariance, PUV.ProjectBaseline0FinishDate
,PUV.ProjectFinishDate, PUV.ProjectFinishVariance, PUV.ProjectActualFinishDate, PUV.ProjectWork, PUV.ProjectBaseline0Work, PUV.ProjectActualWork, PUV.ProjectWorkVariance, PUV.ProjectRemainingWork
,PUV.[Project Phase], PUV.[Hold - Canceled Indicator], CWI.StageName, TB.TB_BASE_NUM, MAX (TB.CREATED_DATE) RecentBaseline
,CASE WHEN PUV.[Estimated Hours] is null then 0 END AS [Estimated%]
,Case When PUV.ProjectActualWork <> 0 THEN cast(COALESCE(PUV.ProjectActualWork,0) as DECIMAL(20,2) )/Cast(COALESCE(PUV.[Estimated Hours],0)as decimal(20,2)) Else 0 End AS [Estimated%]*
--DATEDIFF(day, PUV.ProjectBaseline0FinishDate, PUV.ProjectFinishDate)
FROM MSP_EpmProject_UserView AS PUV
LEFT OUTER JOIN (
SELECT WSI.ProjectUID, WP.PhaseName, WP.PhaseUID, WS.StageName, WS.StageUID
FROM MSP_EpmWorkflowStage AS WS
INNER JOIN MSP_EpmWorkflowPhase AS WP ON WS.PhaseUID = WP.PhaseUID
INNER JOIN MSP_EpmWorkflowStatusInformation AS WSI ON WS.StageUID = WSI.StageUID AND WSI.StageEntryDate IS NOT NULL AND (WSI.StageStatus != 0 AND WSI.StageStatus != 4)
) AS CWI ON PUV.ProjectUID = CWI.ProjectUID
JOIN sps_ppm_IT_Published.dbo.MSP_TASK_BASELINES AS TB ON PUV.ProjectUID = TB.PROJ_UID
WHERE TB.TB_BASE_NUM = 0
GROUP BY PUV.ProjectName, PUV.[Project ID], PUV.[Project Director], PUV.[Project Owner (Manager)], PUV.[Project Type1], PUV.[Estimated Hours]
,PUV.ProjectStatusDate, PUV.ProjectStartDate, PUV.ProjectBaseline0StartDate, PUV.ProjectActualStartDate, PUV.ProjectStartVariance, PUV.ProjectBaseline0FinishDate
,PUV.ProjectFinishDate, PUV.ProjectFinishVariance, PUV.ProjectActualFinishDate, PUV.ProjectWork, PUV.ProjectBaseline0Work, PUV.ProjectActualWork, PUV.ProjectWorkVariance, PUV.ProjectRemainingWork
,PUV.[Project Phase], PUV.[Hold - Canceled Indicator], CWI.StageName, TB.TB_BASE_NUM
ORDER BY PUV.ProjectName
Your title is utterly unrelated to the question and posting a super long, aliased query from your database is not a great way to get help.
Luckily, I was curious enough to see whether "msg-8134-level-16-state-1-line-1" was a secret message from Mars that I checked it out.
Anyway, here's a small example of how to use a CASE statement to avoid division by zero:
SELECT
CASE WHEN example.estimated_hours != 0 AND example.estimated_hours IS NOT NULL
THEN 100 / example.estimated_hours
ELSE 0 END AS ratio
FROM (
SELECT estimated_hours
FROM (
VALUES (0), (1), (NULL), (2), (3))
AS mock_data (estimated_hours))
AS example;
You can just copy/paste that into your SQL terminal and run it to see the output:
ratio
-------
0
100
0
50
33
(5 rows)
Related
My problem is quite simple. The following query returns the error:
Mensagem 537, Level 16, state 2, Line 1
Invalid length parameter passed to the LEFT or SUBSTRING function..
Code:
Select
c.name "Nome Conta",
c.code "Código Conta",
sq1.[Nome Conta] Tipo
From
(chart_tag ct inner join chart c on ct.id_chart = c.id_chart) inner join
(Select
c1.name "Nome Conta",
LEFT(c1.code, (charindex('00', c1.code)-1)) "Código Conta"
from chart_tag ct1 inner join chart c1 on ct1.id_chart = c1.id_chart
where ct1.id_tag = 18159 and
c1.id_type_chart = 1942 and
c1.only_accrual = 1 and
c1.code not in ('99', '98')) sq1 on LEFT(c.code, 1) = sq1.[Código Conta]
Where
ct.id_tag = 18159 and
c.id_type_chart = 1942 and
c.only_accrual = 0
order by
c.code
The first inner join returns the following table:
Name
Code
Caixa Geral
1111001
Caixa Departamentos/Operador
1111005
Valores Recebidos a Depositar
1111025
Bancos Conta Movimento
1112001
Bancos Conta Movimento - Vincul
1112005
Bancos Conta Subvenções
1112021
Bancos Conta Doações
1112022
Bancos Conta Contribuições
1112023
Aplicações Financeiras Imediata
1113001
Aplicações Financeiras Vinc.
1113005
Executing the From subquery separately no errors are returned. The following table is generated:
Name
code
ATIVO
1
ATIVO CIRCULANTE
11
CAIXA E EQUIVALENTES
111
CAIXA
1111
BANCOS
1112
APLICAÇÕES FINANCEIRAS
1113
From
Name
code
ATIVO
1000000
ATIVO CIRCULANTE
1100000
CAIXA E EQUIVALENTES
1110000
CAIXA
1111000
BANCOS
1112000
APLICAÇÕES FINANCEIRAS
1113000
Subquery:
Select
c1.name "Nome Conta",
LEFT(c1.code, (charindex('00', c1.code)-1)) "Código Conta"
from
chart_tag ct1 inner join chart c1 on ct1.id_chart = c1.id_chart
where
ct1.id_tag = 18159 and
c1.id_type_chart = 1942 and
c1.only_accrual = 1 and
c1.code not in ('99', '98')
Changing the main logic, which is to remove the '0' to the right of the "code" column, to use replace the query is executed normally and returning the expected result, except for some lines that deviate from the pattern, containing '0' in the middle of the string , and not just right. Because of this, I thought I'd use the current logic, which is returning the error. Knowing this, the LEFT to which the error refers is that of the subquery, however, as already mentioned, as it is an isolated subquery, which does not depend on external factors, I do not understand the reason for this error.
By the way, if you're simply trying to remove the trailing 0 from the number, have you considered:
REPLACE((RTRIM(REPLACE(c1.code, '0', ' ')),' ', '0')
Change all the 0 to spaces, TRIM, and change residual spaces back..
There'll be more ways to skin the cat;
REVERSE(CAST(REVERSE(c1.code) as INT))
(but reverse is generally regarded as a bit nasty/slow) etc..
So, here's how to debug this:
When you don't use LEFT, you don't get the error
The error message complains that the length passed to LEFT is invalid
The problem is with the LEFT function
The length is passed as the second argument
Replace the c1.code with some value:
Select
LEFT('100', (charindex('00', '100')-1)) "Código Conta"
It works, gives you 1
But.. What if the string you seek isn't found in the value?
Select
LEFT('199', (charindex('00', '199')-1)) "Código Conta"
"Invalid length..." error
So what length are we passing? Extract just the length calc:
Select
charindex('00', '199')-1)
--LEFT('199', (charindex('00', '199')-1)) "Código Conta"
It gives -1, and -1 isn't a valid number of chars to remove from the left of something...
So what do you want to do when the needle isn't found in the haystack? Perhaps take the whole string with no substringing? Or maybe adjust the WHERE clause to only allow codes that end with a 00, so the seek always works?
You decide.. This will give you the whole thing if '00' isn't found:
Select
LEFT(
c1.code,
COALESCE(
NULLIF(
charindex('00', c1.code)-1,
-1
),
LEN(c1.Code)
)
) "Código Conta"
If the seek returns -1 meaning "asn't found", NULLIF converts the -1 to null, and COALESCE then converts the null to the LEN of the string, i.e. LEFT returns the whole thing
This will give empty string if the string isn't found; the only difference is use use of 0 in the coalesce - it asks LEFT to give the leftmost 0 chars:
Select
LEFT(
c1.code,
COALESCE(
NULLIF(
charindex('00', c1.code)-1,
-1
),
0
)
) "Código Conta"
Or, as mentioned, use a WHERE c1.code LIKE '%00%' to ensure youre only looking at codes that really do have 00 in them
If it does not have the substring '00'
LEFT(c1.code, (charindex('00', c1.code)-1))
Will give an error since it return 0 and -1 is not valid
This will work:
CASE WHEN charindex('00', c1.code) > 0
THEN LEFT(c1.code, (charindex('00', c1.code)-1))
ELSE c1.code
END
This will also work:
LEFT(c1.code+'00', (charindex('00', c1.code+'00')-1))
I believe the 2nd one will be faster but it may not be based on your data profile so if performance really matters test both.
I am trying to show the second part below. If a person goes from high to low it is good but if they go from low to high it is bad. Any ideas on how I'd accomplish this? I have the SQL to return the top part but not sure how to get the second part.
you propably looking for lag function
select membno, rancs, date_rank
, case
when lag(rancs, 1, rancs) over (partition by membno order by date_rank) > rancs then 'GOOD'
when lag(rancs, 1, rancs) over (partition by membno order by date_rank) < rancs then 'BAD'
else 'i do''n know'
end second_part_for_current_row
from something
for global resoult use self join:
select curr.membno, prev.rancs, curr.rancs
, case
when prev.rancs > curr.rancs then 'GOOD'
when prev.rancs < curr.rancs then 'BAD'
else 'i do''n know'
end second_part
from something curr
left join something prev on curr.membno = prev.membno and curr.date_rank = prev.date_rank + 1
where not exists (select 1 from something pres where pres.membno = curr.membno and curr.date_rank + 1 = pres.date_rank)
I am trying to run this sum query to produce two columns of Turnover one for TY and another for LY. However, I want any transactions flagged as Cancelled to appear as negatives:
select [Location],BR.BranchName,
sum(case when (FX.TransactionDateKey between '20171101' and '20181031')
and ([Action] = 'Cancelled')
then FX.CustomerValue*-1 else [CustomerValue] end) as [CustmVal TY],
sum(case when (FX.TransactionDateKey between '20161101' and '20171031')
and ([Action] = 'Cancelled')
then FX.CustomerValue*-1 else FX.CustomerValue*1 end) AS [CustmVal LY]
from [dbo].[FRX_Transactions] FX
inner join DWX_Branch BR on BR.BranchID=FX.[Location]
where FX.TransactionDateKey between '20161101' and '20181031' and BR.BusinessDivision = 'Retail'
and FX.[Action] in ('Trade','cancelled') and FX.Reason in ('Public','BBG','Overridesupplyrate') and FX.Operation in ('Add','Del')
group by FX.[Location],BR.BranchName, BR.BranchOpenDate,BR.BranchCloseDate,BR.ActiveStatus
order by BR.BranchName
However, when I run it I get similar data in both columns - it seems to ignore the date conditions.
Please, what am I doing wrong? Is this case-when-statement with TWO conditions written wrong?
Any help would be HUGELY appreciated. Massive thanks!
I think what you actually want for your CASE expression is:
CASE WHEN FX.TransactionDateKey BETWEEN '20171101' AND '20181031' THEN [CustomerValue] *
CASE WHEN [Action] = 'Cancelled' THEN -1 ELSE 1 END
END
I have a query which fetches records from 7 tables. All these tables are JOINed to get the details, few tables used multiple times with different ON clause. So there are 10 JOINs in the query. How can we optimize the query for getting better performance? We already have indexes on JOIN columns. Anything we can do to reduce the number of JOINs? Am using MS SQL 2012 with compatibility level 2008.
Query:
SELECT TOP 100
MT.ProjectId,
matRef,
matDescription,
matKeyDescription,
matOpenDate,
matUFN,
matBranchRef,
matClosedDate,
ERN1.feeRef,
WorkTypeCode,
DPT.deptNo AS matDeptRef,
PreviousRef,
MT.ApplicationID,
MatterCompleted,
CASE WHEN MLC.PFCivil_MatterCount = 0 THEN 0 ELSE 1 END AS IsCPF,
CASE WHEN MLC.PF_MatterCount = 0 THEN 0 ELSE 1 END AS IsPF,
CASE WHEN MLC.Family_MatterCount = 0 THEN 0 ELSE 1 END AS IsFM,
CASE WHEN MLC.WL_MatterCount = 0 THEN 0 ELSE 1 END AS IsWills,
CASE WHEN MLC.Convey_MatterCount = 0 THEN 0 ELSE 1 END AS IsConvey,
CASE WHEN MLC.Probate_MatterCount = 0 THEN 0 ELSE 1 END AS IsProbate,
CASE WHEN MLC.PI_MatterCount = 0 THEN 0 ELSE 1 END AS IsPi,
CASE WHEN MLC.PIPortal_MatterCount = 0 THEN 0 ELSE 1 END AS IsPiPortal,
CASE WHEN MLC.CM_MatterCount = 0 THEN 0 ELSE 1 END AS IsChest,
CASE WHEN MLC.Campaigns_MatterCount = 0 THEN 0 ELSE 1 END AS IsMarketing,
CASE WHEN MLC.PFFamilyFixedFee_MatterCount = 0 THEN 0 ELSE 1 END AS IsPFFamilyFixedFeeMatter,
ERN2.feeRef AS MatPartner,
MatPFCertificateNo,
CASE WHEN MT.matClosedDate = {d''1753-01-01''} THEN 0 ELSE 1 END AS IsArchived,
'''' Modules,
MT.ChargeDescID,
MT.MatterTypeID,
PrimaryClient.ClientName,
MB.LastAccDate,
MB.LastBillDate,
MB.LastClientDate,
MB.LastTimeDate
FROM dbo.Matter AS MT
JOIN dbo.Departments AS DPT ON DPT.deptID = MT.deptID
JOIN dbo.Earners AS ERN1 ON ERN1.MemberId = MT.MatFeeMemId
JOIN dbo.Earners AS ERN2 ON ERN2.MemberId = MT.matPartnerMemId
JOIN dbo.WorkTypes AS WT ON WT.WorkTypeID = MT.WorkTypeID
JOIN dbo.ivw_MatterLinkCount AS MLC ON MLC.ProjectId = MT.ProjectId
JOIN dbo.Banks AS ClientBank ON MT.matClientBank = ClientBank.bankID
JOIN dbo.Banks AS OfficeBank ON MT.matOfficeBank = OfficeBank.bankID
JOIN dbo.Banks AS DepositBank ON MT.matDepositBank = DepositBank.bankID
JOIN uvw_MatterPrimaryClient AS PrimaryClient ON PrimaryClient.ProjectId = MT.ProjectId
JOIN dbo.MatterBalance AS MB ON MT.ProjectId = MB.ProjectID
WHERE matDescription LIKE #Description
ORDER BY Isarchived, matRef
The trick here is that 'WHERE matDescription LIKE #Description' is not the real filter.
The real filter is 'TOP 100' together with 'ORDER BY Isarchived, matRef' because this filter will absolutely filter out anything but 100 rows.
So you need an index at Isarchived, matRef too. Table scan for matRef probably delays this one.
Also unless the Isarchived, matRef combination is unique by constraint, you better add the PK at the end like ORDER BY Isarchived, matRef, matid so there would be no extra problem picking the top 100.
Finally, if Isarchived is something like 0/1 and you have tons of records with 0 value it is useless at order by as there would always be 0. Set it as a filter Isarchived = 0 and remove it from order by - use matRef, matid and add a single index to matRef only.
I have a method (old legacy code) that suddenly started taking much longer time to execute. The only thing that has changed is that I've upgraded from SQL Server 2008 R2 Expr to SQL Server 2014 Expr and therefore started using SMO 2014.
I have a large number of databases, around 180, that I run through to try to find a number of them. The code that runs through them looks like this.
foreach (Database db in instance.Databases)
{
foreach (FileGroup fileGroup in db.FileGroups)
{
foreach (DataFile dataFile in fileGroup.Files)
{
}
}
}
When I find the database I'm looking for the second foreach suddely takes a lot longer to execute, in worst cases up to a minute.
There is no code executing between the second and third foreach.
The code within the third foreach, where I do my stuff, executes fast as usual.
I cant figure out why this is taking so much longer. I've tried to find out if anything has changed in SMO in SQL Server 2014 that could cause this but I've had no luck.
If anyone could give me some idea about where to look I'd appreciate it.
* UPDATE *
This is the query made by SMO 2014 that, according to SQL Profiler, takes time. This query is not made when using SMO 2008 R2
exec sp_executesql N'SELECT
ISNULL((case dmi.mirroring_redo_queue_type when N''UNLIMITED'' then 0 else
dmi.mirroring_redo_queue end),0) AS [MirroringRedoQueueMaxSize],
ISNULL(dmi.mirroring_connection_timeout,0) AS [MirroringTimeout],
ISNULL(dmi.mirroring_partner_name,'''') AS [MirroringPartner],
ISNULL(dmi.mirroring_partner_instance,'''') AS [MirroringPartnerInstance],
ISNULL(dmi.mirroring_role,0) AS [MirroringRole],
ISNULL(dmi.mirroring_safety_level + 1, 0) AS [MirroringSafetyLevel],
ISNULL(dmi.mirroring_state + 1, 0) AS [MirroringStatus],
ISNULL(dmi.mirroring_witness_name,'''') AS [MirroringWitness],
ISNULL(dmi.mirroring_witness_state + 1, 0) AS [MirroringWitnessStatus],
CAST(case when dmi.mirroring_partner_name is null then 0 else 1 end AS bit)
AS [IsMirroringEnabled],
ISNULL(dmi.mirroring_guid,''00000000-0000-0000-0000-0000000000000000'') AS
[MirroringID],
ISNULL(dmi.mirroring_role_sequence,0) AS [MirroringRoleSequence],
ISNULL(dmi.mirroring_safety_sequence,0) AS [MirroringSafetySequence],
ISNULL(dmi.mirroring_failover_lsn,0) AS
[MirroringFailoverLogSequenceNumber],
dtb.is_ansi_null_default_on AS [AnsiNullDefault],
dtb.is_ansi_nulls_on AS [AnsiNullsEnabled],
dtb.is_ansi_padding_on AS [AnsiPaddingEnabled],
dtb.is_ansi_warnings_on AS [AnsiWarningsEnabled],
dtb.is_arithabort_on AS [ArithmeticAbortEnabled],
dtb.is_auto_shrink_on AS [AutoShrink],
dtb.is_cursor_close_on_commit_on AS [CloseCursorsOnCommitEnabled],
dtb.is_concat_null_yields_null_on AS [ConcatenateNullYieldsNull],
dtb.is_numeric_roundabort_on AS [NumericRoundAbortEnabled],
dtb.is_quoted_identifier_on AS [QuotedIdentifiersEnabled],
dtb.is_read_only AS [ReadOnly],
dtb.is_recursive_triggers_on AS [RecursiveTriggersEnabled],
dtb.is_local_cursor_default AS [LocalCursorsDefault],
dtb.page_verify_option AS [PageVerify],
dtb.recovery_model AS [RecoveryModel],
dtb.user_access AS [UserAccess],
dtb.is_db_chaining_on AS [DatabaseOwnershipChaining],
dtb.is_auto_update_stats_async_on AS [AutoUpdateStatisticsAsync],
dtb.is_date_correlation_on AS [DateCorrelationOptimization],
dtb.is_trustworthy_on AS [Trustworthy],
dtb.name AS [Name],
dtb.database_id AS [ID],
dtb.create_date AS [CreateDate],
dtb.is_auto_create_stats_on AS [AutoCreateStatisticsEnabled],
dtb.is_auto_update_stats_on AS [AutoUpdateStatisticsEnabled],
dtb.is_parameterization_forced AS [IsParameterizationForced],
dtb.is_read_committed_snapshot_on AS [IsReadCommittedSnapshotOn],
dtb.is_auto_close_on AS [AutoClose],
dtb.is_broker_enabled AS [BrokerEnabled],
CAST(isnull(dtb.source_database_id, 0) AS bit) AS [IsDatabaseSnapshot],
ISNULL(DB_NAME(dtb.source_database_id), N'''') AS
[DatabaseSnapshotBaseName],
dtb.is_fulltext_enabled AS [IsFullTextEnabled],
dtb.service_broker_guid AS [ServiceBrokerGuid],
dtb.snapshot_isolation_state AS [SnapshotIsolationState],
(dtb.is_published*1+dtb.is_subscribed*2+dtb.is_merge_published*4) AS
[ReplicationOptions],
ISNULL(suser_sname(dtb.owner_sid),'''') AS [Owner],
ISNULL(dtb.log_reuse_wait,0) AS [LogReuseWaitStatus],
drs.recovery_fork_guid AS [RecoveryForkGuid],
drs.database_guid AS [DatabaseGuid],
CAST((case when drs.last_log_backup_lsn is not null then 1 else 0 end) AS
bit) AS [HasFullBackup],
CAST(case when dtb.name in (''master'',''model'',''msdb'',''tempdb'') then 1
else dtb.is_distributor end AS bit) AS [IsSystemObject],
CAST(case when ctb.database_id is null then 0 else 1 end AS bit) AS
[ChangeTrackingEnabled],
CAST(ISNULL(ctb.is_auto_cleanup_on,0) AS bit) AS
[ChangeTrackingAutoCleanUp],
ISNULL(ctb.retention_period,0) AS [ChangeTrackingRetentionPeriod],
CAST(ISNULL(ctb.retention_period_units,0) AS tinyint) AS
[ChangeTrackingRetentionPeriodUnits],
dtb.containment AS [ContainmentType],
dtb.default_language_lcid AS [DefaultLanguageLcid],
dtb.default_language_name AS [DefaultLanguageName],
dtb.default_fulltext_language_lcid AS [DefaultFullTextLanguageLcid],
ISNULL(dtb.default_fulltext_language_name,N'''') AS
[DefaultFullTextLanguageName],
CAST(dtb.is_nested_triggers_on AS bit) AS [NestedTriggersEnabled],
CAST(dtb.is_transform_noise_words_on AS bit) AS [TransformNoiseWords],
dtb.two_digit_year_cutoff AS [TwoDigitYearCutoff],
dtb.target_recovery_time_in_seconds AS [TargetRecoveryTime],
dtb.delayed_durability AS [DelayedDurability],
dtb.is_auto_create_stats_incremental_on AS
[AutoCreateIncrementalStatisticsEnabled],
case
when dtb.collation_name is null then 0x200
else 0
end |
case
when 1 = dtb.is_in_standby then 0x40
else 0
end |
case dtb.state
when 1 then 0x2
when 2 then 0x8
when 3 then 0x4
when 4 then 0x10
when 5 then 0x100
when 6 then 0x20
else 1
end
AS [Status],
CAST(( case LOWER(convert( nvarchar(128), DATABASEPROPERTYEX(dtb.name,
''Updateability''))) when ''read_write'' then 1 else 0 end) AS bit) AS
[IsUpdateable],
CAST(dtb.is_encrypted AS bit) AS [EncryptionEnabled],
CAST(dtb.is_honor_broker_priority_on AS bit) AS [HonorBrokerPriority],
CAST(has_dbaccess(dtb.name) AS bit) AS [IsAccessible],
ISNULL(fsopt.directory_name , N'''') AS [FilestreamDirectoryName],
ISNULL(fsopt.non_transacted_access , 0) AS [FilestreamNonTransactedAccess],
dtb.name AS [DatabaseName2],
dtb.containment AS [ContainmentType2]
FROM
master.sys.databases AS dtb
LEFT OUTER JOIN sys.database_mirroring AS dmi ON dmi.database_id =
dtb.database_id
LEFT OUTER JOIN sys.database_recovery_status AS drs ON drs.database_id =
dtb.database_id
LEFT OUTER JOIN sys.change_tracking_databases AS ctb ON ctb.database_id =
dtb.database_id
LEFT OUTER JOIN sys.database_filestream_options AS fsopt ON
fsopt.database_id = dtb.database_id
WHERE
(dtb.name=#_msparam_0)',N'#_msparam_0 nvarchar(4000)',#_msparam_0=N'2016-11-
03'
Is this query something that has been added to SMO 2014?
Does anyone have an idea about why this is run?