2017-10-19 18 views
0

J'essaie de comprendre comment ajouter ma table html à une CFspreadsheet pour l'afficher dans Excel. Tous les exemples en ligne que j'ai trouvés ne sont pas aussi fous que les miens (une simple requête de base). Toute l'aide pouvant etre apportée serait très appréciée. Voilà ce que je suis en mesure de comprendre jusqu'à présent pour ma feuille de calcul:Ecrire une feuille de calcul en utilisant CFspreadsheet pour éviter toute erreur Ce fichier pourrait être corrompu

<cfset objSpreadsheet = SpreadsheetNew()> 
<cfset filename = expandPath("./myexcel.xls")> 

<!--- Create and format the header row. ---> 
<cfset SpreadsheetAddRow(objSpreadsheet, "Associate Name,Location,Checklists Generated by Associate,Checklists Generated by Selected Location(s),Associate Percentage of Location Total")> 
<cfset SpreadsheetFormatRow(objSpreadsheet, {bold=true, alignment="center"}, 1)> 


<cfheader name="Content-Disposition" value="attachment; filename=#filename#"> 
<cfcontent type="application/vnd.ms-excel" variable="#SpreadsheetReadBinary(objSpreadsheet)#"> 

Ma table en essayant de convertir:

<table class="table table-hover"> 
    <thead> 
     <th><strong>Associate Name</strong></th> 
     <th><strong>Location</strong></th> 
     <th><strong>Checklists Generated by Associate</strong></th> 
     <th><strong>Checklists Generated by Selected Location(s)</strong></th> 
     <th><strong>Associate Percentage of Location Total</strong></th> 
    </thead> 
    <tbody> 
     <cfoutput query="GetEmployeeInfo"> 
     <tr> 
      <td><cfif rnA EQ 1><strong>#assoc_name#</strong></cfif></td> 
      <td><cfif rnL EQ 1>#trans_location#</cfif></td> 
      <td>#checklistsByAssocLoc#</td> 
      <td>#assocChecklistsByLoc#</td> 
      <td>#DecimalFormat(totalChecklistsByAssocLocPct)# %</td> 
      <!---<td> rnA: #rnA# | rnL: #rnL# | rnTotAssoc: #rnTotAssoc# </td> ---> 
     </tr> 
     <cfif rnTotAssoc EQ 1> 
     <tr> 
      <td>Associate Total</td> 
      <td></td> 
      <td>#totalChecklistsByAssoc#</td> 
      <td>#totalAssocChecklistsByAllFilteredLoc#</td> 
      <td>#DecimalFormat(totalChecklistsByLocPct)# %</td> 
     </tr> 
     </cfif> 
    </cfoutput> 
    </tbody> 
</table> 

Mes requêtes folles !:

<cfquery datasource="#application.dsn#" name="GetEmployeeInfo"> 
    SELECT s4.associate /* Associate's ID */ 
     , s4.assoc_name /* Associate's Name */ 
     , s4.trans_location /* Associate's Location */ 
     , s4.checklistsByAssocLoc /* Gives you a count of Checklists by Associate for a specific Location. */ 
     , s4.assocChecklistsByLoc /* Gives you a count of Total Checklists by All Associates in a Location. */ 
     , s4.totalChecklistsByAssoc /** Gives you a count of Total Checklists by Specific Associate in All Locations. */ 
     , s4.totalAssocChecklistsByAllFilteredLoc /* Gives you a count of Total Checklists by Specific Associates in All Locations. */ 
     , CASE WHEN (coalesce(s4.assocChecklistsByLoc,0) > 0) THEN (CAST(s4.checklistsByAssocLoc AS decimal(8,2))/s4.assocChecklistsByLoc) * 100 ELSE 0 END AS totalChecklistsByAssocLocPct /* This gives you a percent of associate location checklists over count of checklists by Associate in a Location. */ 
     , CASE WHEN (coalesce(s4.totalAssocChecklistsByAllFilteredLoc,0) > 0) THEN (CAST(s4.totalChecklistsByAssoc AS decimal(8,2))/s4.totalAssocChecklistsByAllFilteredLoc) * 100 ELSE 0 END AS totalChecklistsByLocPct /* This gives you a percent of Total Associate Checklists in All Locations over count of Checklists by All Associate in All Locations. */ 
     , s4.rnA /* Placeholder for a record to display the Associate Name. */ 
     , s4.rnL /* Placeholder for a record to display the Location. */ 
     , s4.rnTotAssoc /* Placeholder for the last Associate Location row. The next row should be an Associate Total. */ 
    FROM ( 
    SELECT s3.* 
     , SUM(s3.assocChecklistsByLoc) OVER (PARTITION BY s3.associate) AS totalAssocChecklistsByAllFilteredLoc /* Gives you a count of Total Checklists by Specific Associates in All Locations. */ 
    FROM ( 

    SELECT s2.* 
     FROM ( 
      SELECT a.assoc_name 
       , s1.associate 
       , s1.trans_location 
       , s1.checklistsByAssocLoc 
       , s1.assocChecklistsByLoc 
       , s1.totalChecklistsByAssoc 
       , ROW_NUMBER() OVER (PARTITION BY s1.associate ORDER BY s1.associate, s1.trans_location) AS rnA /* Placeholder for a record to display the Associate Name */ 
       , ROW_NUMBER() OVER (PARTITION BY s1.associate, s1.trans_location ORDER BY s1.associate, s1.trans_location) AS rnL /* Placeholder for a record to display the Location */ 
       , ROW_NUMBER() OVER (PARTITION BY s1.associate ORDER BY s1.trans_location DESC) AS rnTotAssoc /* Placeholder for the last Associate Location row. The next row should be an Associate Total. */ 
    FROM ( 
    SELECT c.associate 
     , c.trans_location 
     , COUNT(*) OVER (PARTITION BY c.associate, c.trans_location) AS checklistsByAssocLoc /* Gives you a count of Checklists by Associate for a specific Location. */ 
     , COUNT(*) OVER (PARTITION BY c.associate) AS totalChecklistsByAssoc /* Gives you a count of Total Checklists by Associate in All Locations. */ 
     , COUNT(*) OVER (PARTITION BY c.trans_location) AS assocChecklistsByLoc /* Gives you a count of Total Checklists by All Associates in a Location. */ 
    FROM cl_checklists c 
    LEFT OUTER JOIN tco_associates a ON c.associate = a.assoc_id 
     AND a.assoc_id IN (<cfqueryparam value="#FORM.EmployeeName#" cfsqltype="cf_sql_varchar" list="true" /> ) /* SELECTED ASSOCIATE IDs */ 
      WHERE c.[DATE] >= <cfqueryparam value="#date1#" cfsqltype="cf_sql_timestamp" /> /* SELECTED DATES */ 
       AND c.[DATE] <= <cfqueryparam value="#date2#" cfsqltype="cf_sql_timestamp" /> 
       AND c.trans_location IN (<cfqueryparam value="#locList#" cfsqltype="cf_sql_varchar" list="true" /> ) /* SELECTED LOCATIONS */ 
    ) s1 
    INNER JOIN tco_associates a ON s1.associate = a.assoc_id 
     AND a.assoc_id IN (<cfqueryparam value="#FORM.EmployeeName#" cfsqltype="cf_sql_varchar" list="true" /> ) /* SELECTED ASSOCIATE IDs */ 

    ) s2 
    WHERE s2.rnA = 1 OR s2.rnL = 1 /* There will be a final Location (rnL=1 and rnTotAssoc=1). This is the final row. */ 
    ) s3 
    ) s4 
    ORDER BY s4.assoc_name, s4.trans_location 
</cfquery> 

C'est le chemin que je pensais mais je ne comprends vraiment pas appeler les lignes et les colonnes. Ai-je même la bonne idée ou suis-je loin?

<cfoutput query="GetEmployeeInfo"> 
    <cfif rnA EQ 1><cfset SpreadsheetSetCellValue(objSpreadsheet, #assoc_name#, 2, 1) ></cfif> 
    <cfif rnL EQ 1><cfset SpreadsheetSetCellValue(objSpreadsheet, #trans_location#, 2, 1) ></cfif> 
    <cfset SpreadsheetSetCellValue(objSpreadsheet, #checklistsByAssocLoc#, 2, 1) > 
    <cfset SpreadsheetSetCellValue(objSpreadsheet, #assocChecklistsByLoc#, 2, 1) > 
    <cfset SpreadsheetSetCellValue(objSpreadsheet, #DecimalFormat(totalChecklistsByAssocLocPct)# %, 2, 1) > 
    <cfif rnTotAssoc EQ 1> 
     <cfset SpreadsheetSetCellValue(objSpreadsheet, 'Associate Total', 2, 1) > 
     <cfset SpreadsheetSetCellValue(objSpreadsheet, '', 2, 1) > 
     <cfset SpreadsheetSetCellValue(objSpreadsheet, #totalChecklistsByAssoc#, 2, 1) > 
     <cfset SpreadsheetSetCellValue(objSpreadsheet, #totalAssocChecklistsByAllFilteredLoc#, 2, 1) > 
     <cfset SpreadsheetSetCellValue(objSpreadsheet, #DecimalFormat(totalChecklistsByLocPct)# %, 2, 1) > 
    </cfif> 
</cfoutput> 

a également essayé:

<cfoutput query="GetEmployeeInfo"> 
    <cfset SpreadsheetAddRow(objSpreadsheet, "<cfif rnA EQ 1>#assoc_name#</cfif>,<cfif rnL EQ 1>#trans_location#</cfif>,#checklistsByAssocLoc#,#assocChecklistsByLoc#,#DecimalFormat(totalChecklistsByAssocLocPct)# %")> 
    <cfif rnTotAssoc EQ 1> 
     <cfset SpreadsheetAddRow(objSpreadsheet, "Associate Total,'',#totalChecklistsByAssoc#,#totalAssocChecklistsByAllFilteredLoc#,#DecimalFormat(totalChecklistsByLocPct)# %")> 
    </cfif> 
</cfoutput> 
+1

Alors qu'est-ce qui se passe lorsque vous exécutez ce code? Incluez les messages d'erreur, les traces de pile, etc. Si cela ne fonctionne pas comme prévu, expliquez la différence entre ce qu'il fait et ce que vous voulez qu'il fasse. [ask] –

Répondre

2

Pour votre extrait final, les tags ColdFusion ne seront pas évalués dans un littéral de chaîne. Pour les instructions if else, vous pouvez utiliser l'opérateur ternary pour basculer une partie de la sortie. En outre, si l'une de vos données contient des virgules, elle divise les données entre les cellules. Pour lutter contre cela, essayez d'encapsuler chaque valeur de cellule entre guillemets. Cela peut garder votre texte dans une cellule. .

<cfset rowNumber = 0 /> 
<cfoutput query="GetEmployeeInfo"> 
    <cfset rowNumber++ /> 
    <cfset rowList = "'#(rnA eq 1)?assoc_name:''#', '#(rnl eq 1)?trans_location:''#', '#checklistsByAssocLoc#,#assocChecklistsByLoc#', '#DecimalFormat(totalChecklistsByAssocLocPct)# %'"> 
    <cfset SpreadsheetAddRow(objSpreadsheet, rowList)> 
    <cfset spreadsheetFormatCell(objSpreadsheet, {bold: true}, rowNumber, 1)> 
    <cfif rnTotAssoc EQ 1> 
     <cfset rowNumber++ /> 
     <cfset rowList = "'Associate Total','','#totalChecklistsByAssoc#','#totalAssocChecklistsByAllFilteredLoc#','#DecimalFormat(totalChecklistsByLocPct)# %'" > 
     <cfset SpreadsheetAddRow(objSpreadsheet, rowList)> 
    </cfif> 
</cfoutput> 

Personnellement, en raison de ralentir le temps de rendu de l'utilisation de nombreux (quelques centaines +) spreadsheetAddRow s pour créer une feuille de diffusion, et de travailler avec des listes de données de chaîne peut être une douleur, je place presque toujours mes données de feuille de calcul dans un objet de requête. Une fois que les données sont dans un objet de requête, il faut un appel à spreadsheetAddRows pour obtenir les données dans la feuille de calcul.

qReportData = queryNew("Name, Age", 
    "varchar, integer", 
    [{name: "Tom", age: 25},{name: "Dick", age: 40},{name: "Harry", age: 55}] 
); 
sheet = SpreadsheetNew(false); 

//Add and format headers 
bold = {bold: true}; 
spreadsheetAddRow(sheet, "Name, Age"); 
spreadsheetFormatRow(sheet, bold, 1); 

spreadsheetAddRows(sheet, qReportData); 

Étant donné que certaines de vos données de rapport peuvent être sur plusieurs lignes, dans des situations spécifiques, vous ne serez pas en mesure de simplement exporter votre requête de rapport, donc nous allons devoir construire un nouveau avec le code. Nous parcourons le rapport et générons des lignes dans notre requête de feuille de calcul. Dans mon exemple, je vais ajouter une ligne supplémentaire chaque fois que la personne est âgée de plus de 40.

qSheetOutput = queryNew("Name, Age"); 
for(row in qReportData){ 
    queryAddRow(qSheetOutput, { 
     name: row.name, 
     age: row.age 
    }); 
    if(row.age > 40){ 
     queryAddRow(qSheetOutput, { 
      name: row.name & " is over 40" 
     }); 
    } 
} 
// now writing the generated query to the spreadsheet 
spreadsheetAddRows(sheet, qSheetOutput); 

La dernière étape consistera à itérer et formater les cellules de la feuille de calcul. Comme je critique la sortie, je dois compenser la ligne avec laquelle je travaille par le nombre d'en-têtes dans la feuille, dans cet exemple c'est 1. Dans cet exemple, la ligne supplémentaire pour une personne de plus de 40 ans ne pas être en gras, et s'étendra sur 2 cellules.

for(row in qSheetOutput){ 
    if(!len(row.age)){ 
     spreadsheetFormatCell(sheet, {dataformat="@", alignment="center"}, qSheetOutput.currentRow + 1, 1); 
     spreadsheetFormatCell(sheet, qSheetOutput.currentRow + 1, qSheetOutput.currentRow + 1, 1, 2); 
    } 
    else{ 
     spreadsheetFormatCell(sheet, bold, qSheetOutput.currentRow + 1, 1); 
    } 
} 

Si vous cherchez à la sortie est trop difficile de déterminer le format correct/s nécessaire pour la ligne, vous pouvez itérer sur un tableau/s des numéros de ligne qui nécessitent un format spécifique/s. Encore une fois, notez que j'utilise à nouveau le compte d'en-tête comme décalage.

dataRows = []; 
messageRows = []; 
for(row in qReportData){ 
    queryAddRow(qSheetOutput, { 
     name: row.name, 
     age: row.age 
    }); 
    arrayAppend(dataRows, qSheetOutput.recordCount + 1); 
    if(row.age > 40){ 
     queryAddRow(qSheetOutput, { 
      name: row.name & " is over 40" 
     }); 
     arrayAppend(messageRows, qSheetOutput.recordCount + 1); 
    } 
} 
... 
for(rowNumber in dataRows){ 
    spreadsheetFormatCell(sheet, bold, rowNumber, 1); 
} 
for(rowNumber in messageRows){ 
    spreadsheetFormatCell(sheet, {dataformat="@", alignment="center"}, rowNumber, 1); 
    spreadsheetFormatCell(sheet, rowNumber, rowNumber, 1, 2); 
} 

Voici le code de travail complet sur TryCF.com

+0

Une feuille de calcul connaît la largeur d'une cellule dans le cadre de sa mise en forme, vous pouvez utiliser 'SpreadSheetSetColumnWidth' pour modifier la largeur du champ. Excel n'assume pas une largeur pour la colonne comme il le ferait avec une table html. – Twillen

+0

Laissez-nous [continuer cette discussion dans le chat] (http://chat.stackoverflow.com/rooms/157515/discussion-between-twillen-and-david-brierton). – Twillen

1

En l'honneur de votre persévérance, voici une que je l'ai fait il y a quelques jours. Les variables visitData, headers, columns et title ont été définies plus tôt dans le programme car elles s'appliquaient également à la sortie html.

<cfscript> 
filePath = "d:\dw\dwweb\work\"; 
fileName = title & " " & getTickCount() & ".xlsx"; 

sheet = spreadSheetNew("data", true); 
HeaderFormat = {}; 
HeaderFormat.bold = true; 

spreadSheetAddRow(sheet, headers); 
SpreadSheetFormatRow(sheet, HeaderFormat, 1); 
SpreadSheetAddFreezePane(sheet, 0,1); 

for (queryRow = 1; queryRow <= visitData.recordcount; queryRow ++) { 
rowNumber = queryRow + 1; 
for (columnNumber = 1; columnNumber <= listLen(columns); columnNumber ++) { 
thisColumn = listGetAt(columns, columnNumber); 
thisValue = visitData[thisColumn][queryrow]; 
SpreadSheetSetCellValue(sheet, thisValue, rowNumber, columnNumber); 
} // columns 
} // rows 

SpreadSheetWrite(sheet,filePath & fileName, true); 
</cfscript> 
<cfheader name="content-disposition" value="Attachment;filename=#fileName#"> 
<cfcontent file="#filePath & fileName#" type="application/vnd.ms-excel"> 

Notez les variables que j'utilise dans les deux dernières balises. La balise <cfheader> porte uniquement le nom du fichier, mais pas le chemin. Une erreur que je faisais auparavant était d'utiliser une seule variable qui avait les deux. Le résultat était des noms de fichiers indésirables envoyés à l'utilisateur.

+0

pour filepath cela vous permet-il d'attraper une table à partir d'un fichier .htm, puis de parcourir les champs et de remplir la feuille de calcul? Désolé, je suis encore super confus avec tout cela –