Trying to create a SQL VIEW with multiple criteria in SQLite3 - sql

I'm wondering if it is strait forward enough to create a view in the following way, my attempts are not working as expected,
I'm trying to create another view with the following query that identifies the offending 'grp' when the following condition is true:
original description of my thoughts regarding condition:
SELECT grp FROM control WHERE
('control_1.pvalue' || ' (2nd)' != 'control_2.pvalue')
OR
('control_1.pvalue' || ' (3rd)' != 'control_3.pvalue')
OR
('control_1.pvalue' || ' (4th)' != 'control_4.pvalue')
OR
('control_1.pvalue' || ' (5th)' != 'control_5.pvalue')
OR
('control_1.pvalue' || ' (6th)' != 'control_6.pvalue')
I tried the following expecting to have M2 returned:
SELECT grp FROM control_1 WHERE (pvalue || " (2nd)" != (SELECT pvalue from control_2) AND grp = (SELECT grp from control_2));
But even this basic step is not working for me.
Run the code snippet below to see the table and views that I'm trying to attempt this on.
th, td {border: 1px solid black;}
<div>
<div>CREATE TABLE control (</div>
<div>id INTEGER PRIMARY KEY AUTOINCREMENT,</div>
<div>grp TEXT,</div>
<div>pname TEXT,</div>
<div>pvalue TEXT);</div>
<div></div><br />
<table>
<tr><td colspan="4"><div>control</div></td></tr>
<tr><th>id</th><th>grp</th><th>pname</th><th>pvalue</th></tr>
<tr><td>1</td><td>M1</td><td>d1</td><td>vat</td></tr>
<tr><td>2</td><td>M1</td><td>d2</td><td>vat (2nd)</td></tr>
<tr><td>3</td><td>M1</td><td>d3</td><td>vat (3rd)</td></tr>
<tr><td>4</td><td>M1</td><td>d4</td><td>vat (4th)</td></tr>
<tr><td>5</td><td>M1</td><td>d5</td><td>vat (5th)</td></tr>
<tr><td>6</td><td>M1</td><td>d6</td><td>vat (6th)</td></tr>
<tr><td>7</td><td>M2</td><td>d1</td><td>bin</td></tr>
<tr><td>8</td><td>M2</td><td>d2</td><td>ban (2nd)</td></tr>
<tr><td>9</td><td>M2</td><td>d3</td><td>bin (3rd)</td></tr>
<tr><td>10</td><td>M2</td><td>d4</td><td>bin (4th)</td></tr>
<tr><td>11</td><td>M2</td><td>d5</td><td>bin (5th)</td></tr>
<tr><td>12</td><td>M2</td><td>d6</td><td>bin (6th)</td></tr>
<tr><td>13</td><td>M3</td><td>d1</td><td>haw</td></tr>
<tr><td>14</td><td>M3</td><td>d2</td><td>haw (2nd)</td></tr>
<tr><td>15</td><td>M3</td><td>d3</td><td>ha (3rd)</td></tr>
<tr><td>16</td><td>M3</td><td>d4</td><td>haw (4th)</td></tr>
<tr><td>17</td><td>M3</td><td>d5</td><td>haw (5th)</td></tr>
<tr><td>18</td><td>M3</td><td>d6</td><td>haw (6th)</td></tr>
</table>
<div></div><br />
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d1";</div>
<div></div>
<table>
<tr><th colspan="4">control_1</th></tr>
<tr><th>id</th><th>grp</th><th>pname</th><th>pvalue</th></tr>
<tr><td>1</td><td>M1</td><td>d1</td><td>vat</td></tr>
<tr><td>7</td><td>M2</td><td>d1</td><td>bin</td></tr>
<tr><td>13</td><td>M3</td><td>d1</td><td>haw</td></tr>
</table>
<div></div><br />
<div></div>
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d2";</div>
<div></div>
<table>
<tr><th colspan="4">control_2</th></tr>
<tr><th>id</th><th>grp</th><th>pname</th><th>pvalue</th></tr>
<tr><td>2</td><td>M1</td><td>d2</td><td>vat (2nd)</td></tr>
<tr><td>8</td><td>M2</td><td>d2</td><td>ban (2nd)</td></tr>
<tr><td>14</td><td>M3</td><td>d2</td><td>haw (2nd)</td></tr>
</table>
<div></div><br />
<div>
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d3";</div>
<div></div>
<table>
<tr><th colspan="4">control_3</th></tr>
<tr><th>id</th><th>grp</th><th>pname</th><th>pvalue</th></tr>
<tr><td>3</td><td>M1</td><td>d3</td><td>vat (3rd)</td></tr>
<tr><td>9</td><td>M2</td><td>d3</td><td>bin (3rd)</td></tr>
<tr><td>15</td><td>M3</td><td>d3</td><td>ha (3rd)</td></tr>
</table>
<div></div><br />
<div>
<div>--I create the following as well, but we can see the problems from the 1st three views</div>
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d4";</div>
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d5";</div>
<div>CREATE VIEW control_1 AS SELECT * FROM control WHERE pname = "d6";</div>
</div>

I had an epiphany, and I was able to figure out the following:
I have created two new views as follows, and I'm now getting what I am expecting.
create view dview as
SELECT
DISTINCT
grp,
(select pvalue from control_1 WHERE control.grp == grp) as d1,
(select pvalue from control_2 WHERE control.grp == grp) as d2,
(select pvalue from control_3 WHERE control.grp == grp) as d3,
(select pvalue from control_4 WHERE control.grp == grp) as d4,
(select pvalue from control_5 WHERE control.grp == grp) as d5,
(select pvalue from control_6 WHERE control.grp == grp) as d6
FROM control;
Here's the select statement on this new view:
select * from dview;
grp d1 d2 d3 d4 d5 d6
---------- ---------- ---------- ---------- ---------- ---------- ----------
M1 vat vat (2nd) vat (3rd) vat (4th) vat (5th) vat (6th)
M2 bin ban (2nd) bin (3rd) bin (4th) bin (5th) bin (6th)
M3 haw haw (2nd) ha (3rd) haw (4th) haw (5th) haw (6th)
Begin new view creation:
create view dview_err as
SELECT * FROM dview WHERE
(d1 || " (2nd)" != d2) OR
(d1 || " (3rd)" != d3) OR
(d1 || " (4th)" != d4) OR
(d1 || " (5th)" != d5) OR
(d1 || " (6th)" != d6);
Here's the select statement on this new view:
select grp from dview_err;
grp
----------
M2
M3

Related

Using "for xml" to format SQL results that include results that are NULL?

I have an SQL query basically as follows:
DECLARE #BODY1 NVARCHAR(MAX)
SET #BODY1 = CAST((SELECT td = Name + '</td><td>' + Number + '</td><td>' + Address + '</td>'
FROM
(
SELECT
Name, Number, Address
FROM
Table1
) as Sub
FOR XML PATH('tr'), type) AS VARCHAR(MAX))
SET #BODY1 = '<TABLE CELLPADDING="3" CELLSPACING="3" BORDER="1">'+
'<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR> +
+ REPLACE(REPLACE(#Body1, '<','<'), '>','>') + '</TABLE>'
EXEC MSDB.DBO.SP_SEND_DBMAIL
#PROFILE_NAME = 'NAME',
#RECEPIENTS = 'NAME#DOMAIN.COM',
#BODY = #Body1,
#SUBJECT = 'Details',
#BODY_FORMAT = 'HTML',
#EXECUTE_QUERY_DATABASE = 'NAME';
The data I have can be summarised as follows:
NAME NUMBER ADDRESS
Bob 12345 1 Street, Town
John 23456
Scott 34567 3 Avenue, City
When I run this code which sends me an email containing the results of the query, I only get Bob and Scott's record. This example is simplified, but if there are any rows that do not have data in each field then they do not show in the email.
I've read somewhere that perhaps this is due to needing another variable as part of the XML code, but I can't quite put my finger on what it is. Please can someone assist me?
Thanks in advance.
Your primary issue is that + will return null if any of the values are null. So you could use either ISNULL or CONCAT
But this is in any case not the correct way to create XML. You should just unpivot the values and use FOR XML properly.
DECLARE #BODY1 NVARCHAR(MAX) =
(
SELECT
ISNULL(v.td, '') AS td
FROM
Table1
CROSS APPLY (VALUES
(Name),
(Number),
(Address)
) v(td)
FOR XML PATH('tr')
);
You need to be able to prepare for the entire output of this expression to be NULL:
SET #BODY1 = CAST((SELECT td = Name + '</td><td>'
+ Number + '</td><td>'
+ Address + '</td>' ...
A couple of ways to handle that. You can use COALESCE to convert NULL to empty string:
SET #BODY1 = CAST((SELECT td = COALESCE(Name, '') + '</td><td>'
+ COALESCE(Number, '') + '</td><td>'
+ COALESCE(Address, '') + '</td>' ...
Or CONCAT(), which does that for you:
SET #BODY1 = CAST((SELECT td = CONCAT
(Name, '</td><td>', Number, '</td><td>', Address, '</td>') ...
There are also certainly other approaches to your entire problem space that are a lot less messy, but this is at least a start to get your missing row back.
For example, on SQL Server 2017, you can use STRING_AGG() and CONCAT_WS():
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR><tr>'
+ STRING_AGG('<td>'+CONCAT_WS('</td><td>',Name,Number,Address)
+'</td>','</tr><tr>') + '</tr></table>'
FROM dbo.Table1;
This is also, admittedly, ugly. Another way:
SELECT #BODY1 = '<table ...>
<TR><TH>Name</TH><TH>Number</TH><TH>Address</TH></TR>
<tr>' + td + '</table>'
FROM
(
SELECT td FROM
(
SELECT Name = COALESCE(Name, ''),
Number = COALESCE(Number,''),
Address = COALESCE(Address,'')
FROM dbo.Table1
) AS cp UNPIVOT(td FOR cols IN (Name, Number, Address)) AS up
FOR XML PATH('tr')
) AS x(td);
Please try the following XQuery based approach that gererates XHTML for the email.
Notable points:
No strings concatenation.
No worries for NULL values.
Very easy to create, very easy to maintain.
UI styling is controlled via CSS.
SQL
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, [Name] VARCHAR(20), Number CHAR(5), [Address] VARCHAR(100));
INSERT INTO #tbl (Name, Number, Address) VALUES
('Bob ', '12345' ,'1 Street, Town'),
('John ', '23456' , NULL),
('Scott', '34567' ,'3 Avenue, City');
DECLARE #xhtmlBody XML
, #body NVARCHAR(MAX)
, #tableCaption VARCHAR(30) = 'Customers list';
SET #xhtmlBody = (SELECT (
SELECT * FROM #tbl FOR XML PATH('row'), TYPE, ROOT('root'))
.query('<html><head>
<meta charset="utf-8"/>
(: including embedded CSS styling :)
<style>
table <![CDATA[ {border-collapse: collapse; width: 300px;} ]]>
th <![CDATA[ {background-color: #4CAF50; color: white;} ]]>
th, td <![CDATA[ { text-align: left; padding: 8px;} ]]>
tr:nth-child(even) <![CDATA[ {background-color: #f2f2f2;} ]]>
#green <![CDATA[ {background-color: lightgreen;} ]]>
</style>
</head>
<body>
<table border="1">
<caption><h2>{sql:variable("#tableCaption")}</h2></caption>
<thead>
<tr>
<th>No.</th>
<th>Name</th>
<th>Number</th>
<th>Address</th>
</tr>
</thead>
<tbody>
{
for $row in /root/row
return <tr>
<td>{data($row/ID)}</td>
<td>{data($row/Name)}</td>
<td>{data($row/Number)}</td>
<td>{data($row/Address)}</td>
</tr>
}
</tbody></table></body></html>'));
SELECT #xhtmlBody;
SET #body = CAST(#xhtmlBody AS NVARCHAR(MAX));
Output

Flexible Search Query UNION

I would like to add a UNION to this query , Where exactly Should I put any UNION (doesn't matter the code of the UNION , I just want to know where can I put it) in the following Flexible Search Query (I'm not familiar with the Syntax)
SELECT DISTINCT {o:pk} FROM
(
{{
SELECT
MAX({h.startTime}) AS startTime
FROM {CronJobHistory AS h JOIN CronJobResult AS r ON {h.result} = {r.pk} }
WHERE {h.cronJobCode} = 'ordersCronJob' AND {r.code} = 'SUCCESS'
}}
) LAST,
(
{{
SELECT
MAX({h.startTime}) AS startTime
FROM {CronJobHistory as h}
WHERE {h.cronJobCode} = 'ordersCronJob'
}}
) CURRENT, {Order AS o
JOIN PaymentMode AS pm ON {pm.pk} = {o:paymentMode}
JOIN BaseStore AS b ON {o.store} = {b.PK}
JOIN OrderProcess AS op ON {o.pk} = {op.order}
}
WHERE (({pm:code} != 'asm' AND {op:creationtime} > LAST.startTime AND {op:creationtime} <= CURRENT.startTime)
OR ({pm:code} = 'asm' AND {o:asmActivationTime} > LAST.startTime AND {o:asmActivationTime} <= CURRENT.startTime) )
AND {o:originalVersion} IS NULL
AND 'rows-eu,rows-es' LIKE CONCAT( '%', CONCAT( {b.uid} , '%' ) )
AND {op.processDefinitionName} LIKE 'order-process%'
I've tried putting it in the last line , but it doesn't compile.
Any hint?
For UNION queries or INNER queries, you will need to wrap the respective queries between double curly braces.
{{..query1..}} UNION {{..query2..}}
Check below example for flexible query union sample.
SELECT uniontable.PK, uniontable.CODE FROM
(
{{
SELECT {c:PK} as PK, {c:code} AS CODE FROM {Chapter AS c}
WHERE {c:PUBLICATION} LIKE ?pk
}}
UNION ALL
{{
SELECT {p:PK} as PK, {p:code} AS CODE FROM {Page AS p}
WHERE {p:PUBLICATION} LIKE ?pk
}}
) uniontable
You can find FlexibleSearch Tips and Tricks at
https://help.sap.com/viewer/d0224eca81e249cb821f2cdf45a82ace/1905/en-US/8bc36ba986691014b48be171221d1f4f.html
Hope it helps!
Fixed the first half of your query...
SELECT tbl.startTime FROM
(
{{
SELECT
MAX({h.startTime}) AS startTime
FROM {CronJobHistory AS h JOIN CronJobResult AS r ON {h.result} = {r.pk} }
WHERE {h.cronJobCode} = 'ordersCronJob' AND {r.code} = 'SUCCESS'
}}
UNION
{{
SELECT
MAX({h.startTime}) AS startTime
FROM {CronJobHistory as h}
WHERE {h.cronJobCode} = 'ordersCronJob'
}}
) tbl

SQL how to select data in terms of weeks

Is it in any way possible to select data from the database in spans of weeks?
I use cshtml (not MVC) and webmatrix if that makes any difference.
var dbQueryAllVariants = "SELECT * FROM Test WHERE exercise = " + exercise + " AND date >= '" + fromDate + "' AND date <= '" + toDate + "'";
So right now I'm using this, I put in a start date (ex. 2016-11-01) and end date (ex. 2016-11-30) (yyyy-mm-dd cuz north europe). This displays all the data in the database between those dates but since all rows in the database only have a day as date, the result to be viewed would be in day form, I'd like if it can do weeks, in this case, from first to last november as an example would be aprox 4 weeks, is this possible? Also, the data in the database is int values so I would like to be able to add those up to display a total of the week that gets displayed if that makes sense.
For example.
column 1 column 2 column 3
5 . . . . 6 . . 2016-11-13
8 . . . . 10 . . 2016-11-15
6 . . . . 3 . . 2016-11-17
So as of right now it would display 3 days with a sum of 11 for day 1, 18 for day 2 and 9 for day 3, but while displayed in terms of weeks it would be 11+18+9=38, as for an example. This might not even be possible to begin with but I'd like to know how to do this if possible!
If this isn't a possible solution, is there a way to like select all the data in day form, put it in a array or whatever, and from there send it grouped as a weekly total based on the weeks of the year (ex. november contains week 44-48) something like that? What I'm trying to say is that if the end result is what I want, it doesn't matter how its done.
#{
//Calls for my website layout.
Layout = "~/_SiteLayout.cshtml";
//Browser title of the specific page.
Page.Title = "TEST";
//Opens database.
var db = Database.Open("SmallBakery");
//Variables.
var exercise = Request.Form["Exercise"];
var fromDate = Request.Form["fromDate"];
var toDate = Request.Form["toDate"];
var exerVariName = "";
var exerVariNameS = "";
var exerVariNameB = "";
var exerVariNameD = "";
//Defaults to show data between these
//dates if user dont choose any dates.
var noStartDate = "1970-01/01";
var noEndDate = "2099-12/31";
//If user does not choose eiter/any start/end date
//this will end up showing all results possible.
if (fromDate == "") {
fromDate = noStartDate;
}
if (toDate == "") {
toDate = noEndDate;
}
//Takes exerVariName from different dropdowns
//depending on which exercise is selected due to
//the fact that only one dropdown is visible at any time.
if (exercise == "1") {
exerVariName = Request.Form["exerVariNameS"];
} else if (exercise == "2") {
exerVariName = Request.Form["exerVariNameB"];
} else {
exerVariName = Request.Form["exerVariNameD"];
}
//Gets exercise variants to the dropdown menu.
var getSVariName = "SELECT * FROM exerciseVariants WHERE exerVariNameID = 1 ORDER BY exerVariName";
var getBVariName = "SELECT * FROM exerciseVariants WHERE exerVariNameID = 2 ORDER BY exerVariName";
var getDVariName = "SELECT * FROM exerciseVariants WHERE exerVariNameID = 3 ORDER BY exerVariName";
var getData = "SELECT * FROM Test";
//Gets the date.
var getDate = "SELECT date FROM Test";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<!-- Form for posting. -->
<form method="post" action="">
<!-- Radio buttons to select which data to show. -->
<div>
<label>Squat</label>
<input type="radio" name="Exercise" id="hej1" value="1" />
</div>
<div>
<label>Benchpress</label>
<input type="radio" name="Exercise" id="hej2" value="2" />
</div>
<div>
<label>Deadlift</label>
<input type="radio" name="Exercise" id="hej3" value="3" />
</div>
<div>
<!-- Dropdown menu with squat-variant-names. -->
<select id="exerVariNameS" name="exerVariNameS">
<option value="all">All</option>
<option value="Comp">Competition</option>
#foreach (var get in db.Query(getSVariName)) {
//Gets the exercise variation names from
//the database and puts them in a dropdown.
<option value="#get.exerVariName">#get.exerVariName</option>
}
</select>
<!-- Dropdown menu with bench-variant-names. -->
<select id="exerVariNameB" name="exerVariNameB">
<option value="all">All</option>
<option value="Comp">Competition</option>
#foreach (var get in db.Query(getBVariName)) {
//Gets the exercise variation names from
//the database and puts them in a dropdown.
<option value="#get.exerVariName">#get.exerVariName</option>
}
</select>
<!-- Dropdown menu with deadlift-variant-names. -->
<select id="exerVariNameD" name="exerVariNameD">
<option value="all">All</option>
<option value="Comp">Competition</option>
#foreach (var get in db.Query(getDVariName)) {
//Gets the exercise variation names from
//the database and puts them in a dropdown.
<option value="#get.exerVariName">#get.exerVariName</option>
}
</select>
</div>
<div>
<!-- Date calendar. -->
<input placeholder="From date..." type="text" class="datepicker" name="fromDate" value="#fromDate">
</div>
<div>
<!-- Date calendar. -->
<input placeholder="To date..." type="text" class="datepicker" name="toDate" value="#toDate">
</div>
<!-- The submit button. -->
<input type="submit" value="Show" class="submit" />
</form>
<!-- Displays database value on submit click based on choosen radiobutton from form-post above. -->
#if (IsPost) {
//When I select ALL in the dropdown it runs
//this line because there is no filter for 'exerVariName'.
// var dbQueryAllVariants = "SELECT * FROM Test WHERE exercise = " + exercise + " AND date >= '" + fromDate + "' AND date <= '" + toDate + "'";
//When I select a specific exercise variation.
var dbQuerySingleVariant = "SELECT * FROM Test WHERE exercise = " + exercise + " AND exerVariName = '" + exerVariName + "' AND date >= '" + fromDate + "' AND date <= '" + toDate + "'";
//This is what the problem is....
var dbQueryAllVariants = "SELECT DATEPART(week, date) AS weekNumber, sum(kg)+sum(sett) AS grandTotalPerWeek FROM Test WHERE Exercise = " + exercise + " AND DATEPART(week, date) BETWEEN DATEPART(week, " + fromDate + ") AND DATEPART(week, " + toDate + ") GROUP BY DATEPART(week, date)";
var dbQuery = "";
//If dropdown = select all, it does, else, it show the one I pick.
if (exerVariName == "all") {
dbQuery = dbQueryAllVariants;
} else {
dbQuery = dbQuerySingleVariant;
}
//Foreach to write out all the data from db.
var sumTotalWeight = 0;
foreach (var get in db.Query(dbQuery)) {
<a>Weight: </a>
<a>#get.Kg kg</a>
<a> Sets: </a>
<a>#get.Sett</a>
<a> Reps: </a>
<a>#get.Rep</a>
<a> Total reps: </a>#(get.Sett * get.Rep)
<a> #get.date</a>
var totalWeight = #get.Kg * #get.Sett * #get.Rep;
sumTotalWeight += totalWeight;
<a> #totalWeight</a>
<br>
}
#sumTotalWeight
}
</body>
From your comments one may conclude you are using the MSSQL Server Compact Edition.
If that's correct then you could use the DATEPART function to extract the week of the year for each date, and then group by week and sum all results for each.
Something like this:
SELECT
sum(column1)+sum(column2) AS grandTotalPerWeek
FROM Test
WHERE Exercise = {Exercise}
AND DATEPART(week, date) = {weekNumber}
Where {Exercise} and {weekNumber} are the variables to be substituted.
Or like this, if you need to request multiple weeks at once:
SELECT
DATEPART(week, date) AS weekNumber,
sum(column1)+sum(column2) AS grandTotalPerWeek
FROM Test
WHERE Exercise = {Exercise}
AND DATEPART(week, date) IN ({listOfWeekNumbers})
GROUP BY DATEPART(week, date)
Where {Exercise} and {listOfWeekNumbers} are the variables to be substituted.
In either case, when we talk about week numbers we talk about integer values. 1 means the first week of the year, 2 the second week, ...
Example: Get the values for January
SELECT
DATEPART(week, date) AS weekNumber,
sum(kg)+sum(sett) AS grandTotalPerWeek
FROM Test
WHERE Exercise = 1
AND DATEPART(week, date) IN (1,2,3,4)
GROUP BY DATEPART(week, date)
So, to use this SQL you need to translate dates into week numbers. If you only have dateFrom and dateTo then you can try something like this:
SELECT
DATEPART(week, date) AS weekNumber,
sum(kg)+sum(sett) AS grandTotalPerWeek
FROM Test
WHERE Exercise = 1
AND DATEPART(week, date) BETWEEN DATEPART(week, {dateFrom}) AND DATEPART(week, {dateTo})
GROUP BY DATEPART(week, date)
DATEPART documentation on MSDN.

How to transform path/string by collapsing repeated elements?

There is a filed in my table that represents pathways like below:
Item1->Item1->Item2-> Item3->Item3->Item3->Item1
In most cases this is quite looong sequence with many instances of same consecutive Items.
How I can shorted above path to something like below? in BigQuery!
Item1(x2)->Item2->Item3(x3)->Item1
I wanted to convince myself that this was possible just through array manipulation (using standard SQL), and I came up with a solution. An alternate way to solve the problem would be to use analytic functions, where you could detect changes in item along the path.
CREATE TEMPORARY FUNCTION PartsToString(
parts_and_offsets ARRAY<STRUCT<part STRING, off INT64>>) AS ((
SELECT
STRING_AGG(
CONCAT(part_and_offset.part,
IF(parts_and_offsets[OFFSET(off + 1)].off - part_and_offset.off = 1,
"",
CONCAT("(x", CAST(parts_and_offsets[OFFSET(off + 1)].off - part_and_offset.off AS STRING), ")"))))
FROM UNNEST(parts_and_offsets) AS part_and_offset WITH OFFSET off
WHERE off + 1 < ARRAY_LENGTH(parts_and_offsets)
));
CREATE TEMPORARY FUNCTION PathwayToParts(pathway STRING) AS ((
SELECT
ARRAY_CONCAT(
ARRAY_AGG(
STRUCT(part, off)),
[STRUCT("" AS part, ARRAY_LENGTH(ANY_VALUE(parts)) AS off)]) AS parts_and_offsets
FROM (SELECT SPLIT(pathway, "->") AS parts),
UNNEST(parts) AS part WITH OFFSET off
WHERE off = 0 OR part != parts[OFFSET(off - 1)]
));
WITH YourTable AS (
SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item1->Item1" AS pathway
UNION ALL SELECT "Item1->Item2->Item2" AS pathway
UNION ALL SELECT "Item1->Item1->Item2" AS pathway
UNION ALL SELECT "Item1->Item2->Item3" AS pathway
)
SELECT PartsToString(PathwayToParts(pathway)) AS parts_string
FROM YourTable;
Using Scalar JS UDF (Standard SQL) <-- would be my choice
CREATE TEMPORARY FUNCTION collapse_repeated(pathway STRING)
RETURNS STRING LANGUAGE js AS """
var items = pathway.split('->');
short = ''; elem = items[0]; count = 0;
for (var i = 0; i < items.length; i++) {
if (items[i] !== elem) {
if (short.length > 0) {short += '->'}
short += elem; if (count > 1) {short += '(x' + count.toString() + ')';}
elem = items[i]; count = 1;
} else {
count++;
}
}
if (short.length > 0) {short += '->'}
short += elem; if (count > 1) {short += '(x' + count.toString() + ')';}
return short;
""";
WITH YourTable AS (
SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item1->Item1" AS pathway
UNION ALL SELECT "Item1->Item2->Item2" AS pathway
)
SELECT collapse_repeated(pathway) AS shorten_pathway, pathway
FROM YourTable
Note: Same JS can be easily “translated” to JS UDF in Legacy SQL
Using Window Functions (Legacy SQL)
SELECT GROUP_CONCAT_UNQUOTED(IF(repeats=1, item, CONCAT(item, "(x", STRING(repeats), ")")), "->"), pathway
FROM (
SELECT MIN(pos) AS ord, MIN(item) AS item, COUNT(1) AS repeats, pathway
FROM (
SELECT item, pos, IFNULL(grp, 0)AS grp, pathway FROM (
SELECT item, pos, SUM(change) OVER(PARTITION BY pathway ORDER BY pos ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS grp, pathway
FROM (
SELECT item, pos, IF(item=next_item, 0, 1) AS change, pathway FROM (
SELECT item, pos, LEAD(item) OVER(PARTITION BY pathway ORDER BY pos) AS next_item, pathway
FROM (
SELECT item, POSITION(item) AS pos, pathway FROM (
SELECT SPLIT(pathway, "->") AS item, pathway FROM
(SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway),
(SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway),
(SELECT "Item1->Item1->Item1" AS pathway),
(SELECT "Item1->Item2->Item2" AS pathway)
)
)
)
)
)
)
GROUP BY grp, pathway
ORDER BY ord
)
GROUP BY pathway

data While Cakephp

I'm developing an application with cakephp.
I need to separate the results find('all') for group.
for example my table has the fields: Name; Group.
I want to make a select group by using criteria.
My Controller:
public function print(){
$this->loadModel('Nomevento');
$total = $this->Nomevento->find('count');
$i=1;
while($i<=$total) {
$this->set('grupo', $this->Lista->find('all', array('conditions' => array('Lista.nomevento_id' => $i))));
$i++;
}
}
How do I collect these data in view?
My view:
<?php foreach ($grupo as $grupos): ?>
<table>
<tr>
<td colspan="5" class="tablelinha"><?php echo $grupos['Nomevento']['nome']; ?></td>
</tr>
<tr>
<td class="tablelinha"><?php echo $grupos['Lista']['data']; ?></td>
<td class="tablelinha"><?php echo $grupos['Lista']['dia']; ?></td>
<td class="tablelinha"><?php echo $grupos['Lista']['hora']; ?></td>
<td class="tablelinha"><?php echo $grupos['Igreja']['nome']; ?></td>
<td class="tablelinha"><?php echo $grupos['Responsavel']['responsavel']; ?></td>
<tr><td colspan="5" class="tablelinha"><?php echo $grupos['Lista']['obs']; ?></td></tr>
</tr>
</table><p></p>
The while is working but is displaying only the last result.
My Query:
SELECT COUNT(*) AS `count` FROM `lista_batismo`.`nomeventos` AS `Nomevento` WHERE 1 = 1 SELECT `Lista`.`id`, `Lista`.`data`, `Lista`.`dia`, `Lista`.`hora`, `Lista`.`obs`, `Lista`.`igreja_id`, `Lista`.`responsavel_id`, `Lista`.`nomevento_id`, `Igreja`.`id`, `Igreja`.`codigo_ccb`, `Igreja`.`nome`, `Responsavel`.`id`, `Responsavel`.`responsavel`, `Responsavel`.`comum`, `Nomevento`.`id`, `Nomevento`.`nome`, `Nomevento`.`prioridade` FROM `lista_batismo`.`listas` AS `Lista` LEFT JOIN `lista_batismo`.`igrejas` AS `Igreja` ON (`Lista`.`igreja_id` = `Igreja`.`id`) LEFT JOIN `lista_batismo`.`responsavels` AS `Responsavel` ON (`Lista`.`responsavel_id` = `Responsavel`.`id`) LEFT JOIN `lista_batismo`.`nomeventos` AS `Nomevento` ON (`Lista`.`nomevento_id` = `Nomevento`.`id`) WHERE `Lista`.`nomevento_id` = 1 SELECT `Lista`.`id`, `Lista`.`data`, `Lista`.`dia`, `Lista`.`hora`, `Lista`.`obs`, `Lista`.`igreja_id`, `Lista`.`responsavel_id`, `Lista`.`nomevento_id`, `Igreja`.`id`, `Igreja`.`codigo_ccb`, `Igreja`.`nome`, `Responsavel`.`id`, `Responsavel`.`responsavel`, `Responsavel`.`comum`, `Nomevento`.`id`, `Nomevento`.`nome`, `Nomevento`.`prioridade` FROM `lista_batismo`.`listas` AS `Lista` LEFT JOIN `lista_batismo`.`igrejas` AS `Igreja` ON (`Lista`.`igreja_id` = `Igreja`.`id`) LEFT JOIN `lista_batismo`.`responsavels` AS `Responsavel` ON (`Lista`.`responsavel_id` = `Responsavel`.`id`) LEFT JOIN `lista_batismo`.`nomeventos` AS `Nomevento` ON (`Lista`.`nomevento_id` = `Nomevento`.`id`) WHERE `Lista`.`nomevento_id` = 2 SELECT `Lista`.`id`, `Lista`.`data`, `Lista`.`dia`, `Lista`.`hora`, `Lista`.`obs`, `Lista`.`igreja_id`, `Lista`.`responsavel_id`, `Lista`.`nomevento_id`, `Igreja`.`id`, `Igreja`.`codigo_ccb`, `Igreja`.`nome`, `Responsavel`.`id`, `Responsavel`.`responsavel`, `Responsavel`.`comum`, `Nomevento`.`id`, `Nomevento`.`nome`, `Nomevento`.`prioridade` FROM `lista_batismo`.`listas` AS `Lista` LEFT JOIN `lista_batismo`.`igrejas` AS `Igreja` ON (`Lista`.`igreja_id` = `Igreja`.`id`) LEFT JOIN `lista_batismo`.`responsavels` AS `Responsavel` ON (`Lista`.`responsavel_id` = `Responsavel`.`id`) LEFT JOIN `lista_batismo`.`nomeventos` AS `Nomevento` ON (`Lista`.`nomevento_id` = `Nomevento`.`id`) WHERE `Lista`.`nomevento_id` = 3 SELECT `Lista`.`id`, `Lista`.`data`, `Lista`.`dia`, `Lista`.`hora`, `Lista`.`obs`, `Lista`.`igreja_id`, `Lista`.`responsavel_id`, `Lista`.`nomevento_id`, `Igreja`.`id`, `Igreja`.`codigo_ccb`, `Igreja`.`nome`, `Responsavel`.`id`, `Responsavel`.`responsavel`, `Responsavel`.`comum`, `Nomevento`.`id`, `Nomevento`.`nome`, `Nomevento`.`prioridade` FROM `lista_batismo`.`listas` AS `Lista` LEFT JOIN `lista_batismo`.`igrejas` AS `Igreja` ON (`Lista`.`igreja_id` = `Igreja`.`id`) LEFT JOIN `lista_batismo`.`responsavels` AS `Responsavel` ON (`Lista`.`responsavel_id` = `Responsavel`.`id`) LEFT JOIN `lista_batismo`.`nomeventos` AS `Nomevento` ON (`Lista`.`nomevento_id` = `Nomevento`.`id`) WHERE `Lista`.`nomevento_id` = 4
Thanks for your attention;
It looks your are counting records so it would return only INT.
I wouldn't use $this->loadModel('Nomevento'); You should define properly relations between your models (Nomevento and Lista).