Tengo una columna en DQ que se almacena en formato HTML

Un usuario Pregunto ✅

ukeasyproj

¿Hay alguna forma de convertir esta columna en texto normal?

prueba.PNG

Hola @ukeasyproj,

En su escenario, primero deberá eliminar las etiquetas HTML en la fuente de datos de SQL Server y luego cargar los datos de la base de datos de SQL Server a Power BI usando el modo DirectQuery. Por favor revise los siguientes pasos detallados.

1. Cree una función en su base de datos usando los siguientes códigos.

IF OBJECT_ID(N'dbo.RegexReplace') IS NOT NULL 
   DROP FUNCTION dbo.RegexReplace
GO
CREATE FUNCTION dbo.RegexReplace
(
  @pattern VARCHAR(255),
  @replacement VARCHAR(255),
  @Subject VARCHAR(MAX),
  @global BIT = 1,
 @Multiline bit =1
)
RETURNS VARCHAR(MAX)

AS BEGIN
DECLARE @objRegexExp INT,
    @objErrorObject INT,
    @strErrorMessage VARCHAR(255),
    @Substituted VARCHAR(8000),
    @hr INT,
    @Replace BIT

SELECT  @strErrorMessage="creating a regex object"
EXEC @hr= sp_OACreate 'VBScript.RegExp', @objRegexExp OUT
IF @hr = 0 
    SELECT  @strErrorMessage="Setting the Regex pattern",
            @objErrorObject = @objRegexExp
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'Pattern', @pattern
IF @hr = 0 /*By default, the regular expression is case sensitive. Set the IgnoreCase property to True to make it case insensitive.*/
    SELECT  @strErrorMessage="Specifying the type of match" 
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'IgnoreCase', 1
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'MultiLine', @Multiline
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'Global', @global
IF @hr = 0 
    SELECT  @strErrorMessage="Doing a Replacement" 
IF @hr = 0 
    EXEC @hr= sp_OAMethod @objRegexExp, 'Replace', @Substituted OUT,
        @subject, @Replacement
 /*If the RegExp.Global property is False (the default), Replace will return the @subject string with the first regex match (if any) substituted with the replacement text. If RegExp.Global is true, the @Subject string will be returned with all matches replaced.*/   
IF @hr <> 0 
    BEGIN
        DECLARE @Source VARCHAR(255),
            @Description VARCHAR(255),
            @Helpfile VARCHAR(255),
            @HelpID INT

        EXECUTE sp_OAGetErrorInfo @objErrorObject, @source OUTPUT,
            @Description OUTPUT, @Helpfile OUTPUT, @HelpID OUTPUT
        SELECT  @strErrorMessage="Error whilst "
                + COALESCE(@strErrorMessage, 'doing something') + ', '
                + COALESCE(@Description, '')
        RETURN @strErrorMessage
    END
EXEC sp_OADestroy @objRegexExp
RETURN @Substituted
END
Go

2. Luego use esta función para eliminar las etiquetas HTML de su columna, hay una referencia de ejemplo cuatro. Mi tabla original se ve a continuación.
1.png

3. Cambie los ajustes de configuración con los siguientes códigos; de lo contrario, recibirá el mensaje de error «SQL Server bloqueó el acceso al procedimiento ‘sys.sp_OACreate’ del componente ‘Ole Automation Procedures’ porque este componente está desactivado como parte de la configuración de seguridad de este servidor ” al ejecutar declaraciones de actualización en el paso 4.

sp_configure'show advanced options', 1 
GO 
RECONFIGURE; 
GO 
sp_configure'Ole Automation Procedures', 1 
GO 
RECONFIGURE; 
GO 
sp_configure'show advanced options', 1 
GO 
RECONFIGURE;

4. Actualice el campo HTML usando la función creada en el Paso 1.
2 PNG

5. Importe datos de la base de datos de SQL Server a Power BI Desktop.

3.png

Gracias,
Lidia Zhang

Hola @ukeasyproj,

En su escenario, primero deberá eliminar las etiquetas HTML en la fuente de datos de SQL Server y luego cargar los datos de la base de datos de SQL Server a Power BI usando el modo DirectQuery. Por favor revise los siguientes pasos detallados.

1. Cree una función en su base de datos usando los siguientes códigos.

IF OBJECT_ID(N'dbo.RegexReplace') IS NOT NULL 
   DROP FUNCTION dbo.RegexReplace
GO
CREATE FUNCTION dbo.RegexReplace
(
  @pattern VARCHAR(255),
  @replacement VARCHAR(255),
  @Subject VARCHAR(MAX),
  @global BIT = 1,
 @Multiline bit =1
)
RETURNS VARCHAR(MAX)

AS BEGIN
DECLARE @objRegexExp INT,
    @objErrorObject INT,
    @strErrorMessage VARCHAR(255),
    @Substituted VARCHAR(8000),
    @hr INT,
    @Replace BIT

SELECT  @strErrorMessage="creating a regex object"
EXEC @hr= sp_OACreate 'VBScript.RegExp', @objRegexExp OUT
IF @hr = 0 
    SELECT  @strErrorMessage="Setting the Regex pattern",
            @objErrorObject = @objRegexExp
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'Pattern', @pattern
IF @hr = 0 /*By default, the regular expression is case sensitive. Set the IgnoreCase property to True to make it case insensitive.*/
    SELECT  @strErrorMessage="Specifying the type of match" 
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'IgnoreCase', 1
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'MultiLine', @Multiline
IF @hr = 0 
    EXEC @hr= sp_OASetProperty @objRegexExp, 'Global', @global
IF @hr = 0 
    SELECT  @strErrorMessage="Doing a Replacement" 
IF @hr = 0 
    EXEC @hr= sp_OAMethod @objRegexExp, 'Replace', @Substituted OUT,
        @subject, @Replacement
 /*If the RegExp.Global property is False (the default), Replace will return the @subject string with the first regex match (if any) substituted with the replacement text. If RegExp.Global is true, the @Subject string will be returned with all matches replaced.*/   
IF @hr <> 0 
    BEGIN
        DECLARE @Source VARCHAR(255),
            @Description VARCHAR(255),
            @Helpfile VARCHAR(255),
            @HelpID INT

        EXECUTE sp_OAGetErrorInfo @objErrorObject, @source OUTPUT,
            @Description OUTPUT, @Helpfile OUTPUT, @HelpID OUTPUT
        SELECT  @strErrorMessage="Error whilst "
                + COALESCE(@strErrorMessage, 'doing something') + ', '
                + COALESCE(@Description, '')
        RETURN @strErrorMessage
    END
EXEC sp_OADestroy @objRegexExp
RETURN @Substituted
END
Go

2. Luego use esta función para eliminar etiquetas HTML de su columna, hay una referencia de ejemplo cuatro. Mi tabla original se ve a continuación.
1.png

3. Cambie los ajustes de configuración con los siguientes códigos; de lo contrario, recibirá el mensaje de error «SQL Server bloqueó el acceso al procedimiento ‘sys.sp_OACreate’ del componente ‘Ole Automation Procedures’ porque este componente está desactivado como parte de la configuración de seguridad de este servidor ” al ejecutar declaraciones de actualización en el paso 4.

sp_configure'show advanced options', 1 
GO 
RECONFIGURE; 
GO 
sp_configure'Ole Automation Procedures', 1 
GO 
RECONFIGURE; 
GO 
sp_configure'show advanced options', 1 
GO 
RECONFIGURE;

4. Actualice el campo HTML usando la función creada en el Paso 1.
2 PNG

5. Importe datos de la base de datos de SQL Server a Power BI Desktop.

3.png

Gracias,
Lidia Zhang

Marcel Beug

Coincidentemente, recientemente creé una función recursiva (PowerQuery/M) para eliminar etiquetas HTML.

Tiene 4 argumentos (de los cuales 2 son opcionales para ejecutar la función en modo de prueba):
Cuerda,
Posición de inicio (normalmente 0 para empezar)
Iteración actual opcional (normalmente 1 para empezar)
Número máximo opcional de iteraciones.

        fnRHTMLT = (String as text, StartPosition as number, optional Iteration as number, optional MaxIterations as number) as text =>
        let
            StringFromStartposition = Text.RemoveRange(String, 0, StartPosition),
            StartPositionEndTag = Text.PositionOf(StringFromStartposition, "</"),
            PositionsEndTag = if StartPositionEndTag = -1 
                                then -1 
                                else Text.PositionOf(Text.RemoveRange(StringFromStartposition, 0, StartPositionEndTag),">"),
            StartTag = if PositionsEndTag = -1 
                       then null 
                       else "<" & Text.Range(StringFromStartposition, StartPositionEndTag + 2, PositionsEndTag - 1),
            StartPositionStartTag = if PositionsEndTag = -1 
                                    then -1 
                                    else Text.PositionOf(Text.Start(String,StartPosition + StartPositionEndTag),StartTag,Occurrence.Last),
            NewString = if StartPositionStartTag = -1 
                        then String 
                        else Text.RemoveRange(Text.RemoveRange(String,StartPosition + StartPositionEndTag, PositionsEndTag + 1),StartPositionStartTag, PositionsEndTag),
            NextStartPosition = if PositionsEndTag = -1
                                then -1
                                else if StartPositionStartTag = -1
                                     then StartPosition + StartPositionEndTag + 1
                                     else StartPosition + StartPositionEndTag - PositionsEndTag,
            Result = if NextStartPosition = -1
                     then NewString
                     else if Iteration = null 
                          then @fnRHTMLT(NewString, NextStartPosition)
                          else if Iteration = MaxIterations
                               then NewString
                               else @fnRHTMLT(NewString, NextStartPosition, Iteration + 1, MaxIterations)

        in
            Result

ukeasyproj

En respuesta a Marcel Beug

@MarcelBeug

Hola, soy nuevo en power bi, en el editor de consultas, ¿dónde necesitaría insertar su código?

Marcel Beug

En respuesta a ukeasyproj

Puede incorporar el código en su consulta en el Editor avanzado.

Ejemplo:

let
    <Insert the function here followed by a comma>,
    TableWithDescription = Table.FromList({"<BODY><p>MarcelBeug</p></BODY>"},null,type table[Description = text]),
    #"Added Custom" = Table.AddColumn(TableWithDescription, "HTMLRemoved", each fnRHTMLT([Description],0))
in
    #"Added Custom"

ukeasyproj

En respuesta a Marcel Beug

@MarcelBeug

Esta es mi consulta actual de la siguiente manera:

let
    Source = Sql.Database(ServerName, DatabaseName),
    dbo_TT_Projects = Source{[Schema="dbo",Item="TT_Projects"]}[Data],
    #"Filtered Rows" = Table.SelectRows(dbo_TT_Projects, each [AccountId] = AccountID),
    #"Removed Other Columns" = Table.SelectColumns(#"Filtered Rows",{"ProjectID", "Name", "EndDate", "ActCompletionDate", "Duration", "StartDate", "CreationDate", "ProjectStatusID", "BillingType", "BillingAmount", "PriorityID", "Progress", "CustomerID", "CreatorID", "EstimatedHours", "Description", "Budget", "PortfolioID", "Billed", "MD_ProjectFields"}),
    #"Expanded MD_ProjectFields" = Table.ExpandTableColumn(#"Removed Other Columns", "MD_ProjectFields", {"ProjectDECIMAL0", "ProjectDECIMAL1", "ProjectDECIMAL2", "ProjectDECIMAL3", "ProjectDECIMAL4", "ProjectDATETIME0", "ProjectDATETIME1", "ProjectDATETIME2", "ProjectDATETIME3", "ProjectDATETIME4", "ProjectDATETIME5"}, {"ProjectDECIMAL0", "ProjectDECIMAL1", "ProjectDECIMAL2", "ProjectDECIMAL3", "ProjectDECIMAL4", "ProjectDATETIME0", "ProjectDATETIME1", "ProjectDATETIME2", "ProjectDATETIME3", "ProjectDATETIME4", "ProjectDATETIME5"}),
    #"Renamed CustomFields" = Table.RenameColumns(#"Expanded MD_ProjectFields",{{"ProjectDATETIME1", "Original End Date"}, {"ProjectDATETIME2", "Q1 End Date"}, {"ProjectDATETIME3", "Q2 End Date"}, {"ProjectDATETIME4", "Q3 End Date"}, {"ProjectDATETIME5", "Q4 End Date"}, {"ProjectDECIMAL0", "Original Estimated Hours"}, {"ProjectDECIMAL1", "Q1"}, {"ProjectDECIMAL2", "Q2"}, {"ProjectDECIMAL3", "Q3"}, {"ProjectDECIMAL4", "Q4"}}),
    #"Renamed Columns" = Table.RenameColumns(#"Renamed CustomFields",{{"Name", "Project Name"}, {"StartDate", "Start Date"}, {"EndDate", "End Date"}, {"ProjectDATETIME0", "PO ACK DATE"}})
in
    #"Renamed Columns"

Todavía confundido dónde debo poner su función, la columna en la que quiero invocarla se llama Descripción

Marcel Beug

En respuesta a ukeasyproj

Puede poner el código entre «let» y «Source». Y no olvide poner una coma después de «Resultado».

Ahora puede usar la función, por ejemplo, agregando una columna personalizada con el código: fnRHTMLT([Description],0)

ukeasyproj

En respuesta a Marcel Beug

let

   fnRHTMLT = (String as text, StartPosition as number, optional Iteration as number, optional MaxIterations as number) as text =>
        let
            StringFromStartposition = Text.RemoveRange(String, 0, StartPosition),
            StartPositionEndTag = Text.PositionOf(StringFromStartposition, "</"),
            PositionsEndTag = if StartPositionEndTag = -1 
                                then -1 
                                else Text.PositionOf(Text.RemoveRange(StringFromStartposition, 0, StartPositionEndTag),">"),
            StartTag = if PositionsEndTag = -1 
                       then null 
                       else "<" & Text.Range(StringFromStartposition, StartPositionEndTag + 2, PositionsEndTag - 1),
            StartPositionStartTag = if PositionsEndTag = -1 
                                    then -1 
                                    else Text.PositionOf(Text.Start(String,StartPosition + StartPositionEndTag),StartTag,Occurrence.Last),
            NewString = if StartPositionStartTag = -1 
                        then String 
                        else Text.RemoveRange(Text.RemoveRange(String,StartPosition + StartPositionEndTag, PositionsEndTag + 1),StartPositionStartTag, PositionsEndTag),
            NextStartPosition = if PositionsEndTag = -1
                                then -1
                                else if StartPositionStartTag = -1
                                     then StartPosition + StartPositionEndTag + 1
                                     else StartPosition + StartPositionEndTag - PositionsEndTag,
            Result = if NextStartPosition = -1
                     then NewString
                     else if Iteration = null 
                          then @fnRHTMLT(NewString, NextStartPosition)
                          else if Iteration = MaxIterations
                               then NewString
                               else @fnRHTMLT(NewString, NextStartPosition, Iteration + 1, MaxIterations)

        in
            Result,



    Source = Sql.Database(ServerName, DatabaseName),
    dbo_TT_Projects = Source{[Schema="dbo",Item="TT_Projects"]}[Data],
    #"Filtered Rows" = Table.SelectRows(dbo_TT_Projects, each [AccountId] = AccountID),
    #"Removed Other Columns" = Table.SelectColumns(#"Filtered Rows",{"ProjectID", "Name", "EndDate", "ActCompletionDate", "Duration", "StartDate", "CreationDate", "ProjectStatusID", "BillingType", "BillingAmount", "PriorityID", "Progress", "CustomerID", "CreatorID", "EstimatedHours", "Description", "Budget", "PortfolioID", "Billed", "MD_ProjectFields"}),
    #"Expanded MD_ProjectFields" = Table.ExpandTableColumn(#"Removed Other Columns", "MD_ProjectFields", {"ProjectDECIMAL0", "ProjectDECIMAL1", "ProjectDECIMAL2", "ProjectDECIMAL3", "ProjectDECIMAL4", "ProjectDATETIME0", "ProjectDATETIME1", "ProjectDATETIME2", "ProjectDATETIME3", "ProjectDATETIME4", "ProjectDATETIME5"}, {"ProjectDECIMAL0", "ProjectDECIMAL1", "ProjectDECIMAL2", "ProjectDECIMAL3", "ProjectDECIMAL4", "ProjectDATETIME0", "ProjectDATETIME1", "ProjectDATETIME2", "ProjectDATETIME3", "ProjectDATETIME4", "ProjectDATETIME5"}),
    #"Renamed CustomFields" = Table.RenameColumns(#"Expanded MD_ProjectFields",{{"ProjectDATETIME1", "Original End Date"}, {"ProjectDATETIME2", "Q1 End Date"}, {"ProjectDATETIME3", "Q2 End Date"}, {"ProjectDATETIME4", "Q3 End Date"}, {"ProjectDATETIME5", "Q4 End Date"}, {"ProjectDECIMAL0", "Original Estimated Hours"}, {"ProjectDECIMAL1", "Q1"}, {"ProjectDECIMAL2", "Q2"}, {"ProjectDECIMAL3", "Q3"}, {"ProjectDECIMAL4", "Q4"}}),
    #"Renamed Columns" = Table.RenameColumns(#"Renamed CustomFields",{{"Name", "Project Name"}, {"StartDate", "Start Date"}, {"EndDate", "End Date"}, {"ProjectDATETIME0", "PO ACK DATE"}}),
    #"Added Custom" = Table.AddColumn(dbo_TT_Projects, "HTMLRemoved", each fnRHTMLT([Description],0))

in
    #"Added Custom"

Hice lo siguiente, pero recibí un error que decía que no es compatible con el modo DirectQuery

Marcel Beug

En respuesta a ukeasyproj

Lo siento, no he tenido en cuenta ninguna limitación de consulta directa.

No puedo pensar en ninguna alternativa que funcione en modo DQ.
Tal vez se podría hacer algo en su entorno de base de datos, pero eso estaría fuera de mi alcance.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *