I have a table containing pipes that are installed at a location.
Installed dates are always filled in, removed dates can be NULL
Type Installed Removed Length
PT2 01/01/2011 NULL 2000
PT2 01/01/2011 NULL 2000
PT1 01/01/2011 NULL 1200
PT1 01/01/2011 NULL 1200
PT1 15/02/2011 25/02/2011 1000
PT1 15/02/2011 25/02/2011 1000
Now I need an overview of the total length per type that was installed for a given month, so the result should be for example from 01/02/2011 to 28/02/2011:
Type From To Length
PT2 01/02/2011 28/02/2011 4000
PT1 01/02/2011 14/02/2011 2400
PT1 15/02/2011 24/02/2011 4400 Edit: (starts on 15 not 14)
PT1 25/02/2011 28/02/2011 2400
EDIT: Clarification on this expected result.
In the end this will be used to see the total length of pipe at any given moment during the requested month. So if you look at the table above, during February 2 PT2 pipes were installed. They were installed in January, but are still present, so during the entire month there is a total length of 4000.
Same for PT1: From the start of February 2 PT1 pipes are installed, so 2400. However on the 15th an extra 2 PT1 pipes of length 1000 are installed so during the 15th to the 25th the total length of PT1 pipes is 4400.
These 2 pipes are removed on the 25th so 25 to end of month it's 2400 again.
I hope this makes a little more sense now.
I'm struggling with how to do this in SQL, It's for a report, and generally there are hundreds of these pipes installed in any given month.
It's for use in a Powerbuilder application, so if you know any datawindow trickery that might help feel free to share.
Having too much fun with this! I've taken a few liberties, like assuming a sort order, and changing your query criteria to a date range instead of declaring a month.
To start with, I changed the data set from date ranges to dates of changes and quantity of changes (positive values on installation date, negative values on removal date).
SELECT type,
installed as date_of_change,
length change_of_length
FROM pipes
WHERE (installed BETWEEN :date_start AND
:date_end) OR
((installed < :date_start) AND
(isnull (removed, :date_end) >= :date_start))
UNION ALL
SELECT type,
isnull (removed, dateadd (day, 1, :date_end)),
(length * -1)
FROM pipes
WHERE (installed BETWEEN :date_start AND
:date_end) OR
((installed < :date_start) AND
(isnull (removed, :date_end) >= :date_start))
ORDER BY type,
date_of_change
And, yes, those colons in front of the arguments (I've switched you to start and end dates... easier for me and now you can do six month reports) means I'm leveraging a DataWindow. (I'm betting someone can create a pure SQL approach with the above concept change, but I'm going with what I know.)
Load the SQL into a DataWindow (I used freeform), and optionally set a client-side sort by type and date_of_change (belt and suspenders). The data set includes null Removed dates as a change the day after the end of your query range, so create a filter to exclude those nulls:
date_of_change <= date_end
Create a group based on type, and put type into the group header.
In the detail band (where all subsequent controls are going), create a compute called date_from with the following expression:
if (date_of_change < date_start, date_start, date_of_change)
Create a compute called date_to with the following expression:
if (type = type[1] and getrow() < rowcount() and date_of_change[1] <= date_end,
RelativeDate(date_of_change[1], -1), date_end )
Create a compute called installed_length with the following expression:
cumulativesum ( change_of_length FOR GROUP 1)
Select all the controls in your detail band and give them a Visible expression of:
if (date_of_change = date_of_change [1] and type = type[1], 0, 1)
which will make them invisible if the next row has the same date_of_change and type; you only want the last row to show with the sum of all of today's activities.
Drag the detail band to height of zero, and make the detail band autosize height.
That will give you a version of what you're after. FWIW, I tried to make the report sort on date (not clear if that's what you wanted, or sorted first on type), but it breaks the CumulativeSum() functionality. Maybe someone else can figure it out.
Good luck,
Terry.
P.S. If SO lets me put this much in, here's the export of my prototype. It may or may not be useful to you.
release 11.5;
datawindow(units=0 timer_interval=0 color=1073741824 brushmode=0 transparency=0 gradient.angle=0 gradient.color=8421504 gradient.focus=0 gradient.repetition.count=0 gradient.repetition.length=100 gradient.repetition.mode=0 gradient.scale=100 gradient.spread=100 gradient.transparency=0 picture.blur=0 picture.clip.bottom=0 picture.clip.left=0 picture.clip.right=0 picture.clip.top=0 picture.mode=0 picture.scale.x=100 picture.scale.y=100 picture.transparency=0 processing=0 HTMLDW=no print.printername="" print.documentname="" print.orientation = 0 print.margin.left = 110 print.margin.right = 110 print.margin.top = 96 print.margin.bottom = 96 print.paper.source = 0 print.paper.size = 0 print.canusedefaultprinter=yes print.prompt=no print.buttons=no print.preview.buttons=no print.cliptext=no print.overrideprintjob=no print.collate=yes print.background=no print.preview.background=no print.preview.outline=yes hidegrayline=no showbackcoloronxp=no picture.file="" )
header(height=72 color="536870912" transparency="0" gradient.color="8421504" gradient.transparency="0" gradient.angle="0" brushmode="0" gradient.repetition.mode="0" gradient.repetition.count="0" gradient.repetition.length="100" gradient.focus="0" gradient.scale="100" gradient.spread="100" )
summary(height=0 color="536870912" transparency="0" gradient.color="8421504" gradient.transparency="0" gradient.angle="0" brushmode="0" gradient.repetition.mode="0" gradient.repetition.count="0" gradient.repetition.length="100" gradient.focus="0" gradient.scale="100" gradient.spread="100" )
footer(height=0 color="536870912" transparency="0" gradient.color="8421504" gradient.transparency="0" gradient.angle="0" brushmode="0" gradient.repetition.mode="0" gradient.repetition.count="0" gradient.repetition.length="100" gradient.focus="0" gradient.scale="100" gradient.spread="100" )
detail(height=0 color="536870912" transparency="0" gradient.color="8421504" gradient.transparency="0" gradient.angle="0" brushmode="0" gradient.repetition.mode="0" gradient.repetition.count="0" gradient.repetition.length="100" gradient.focus="0" gradient.scale="100" gradient.spread="100" height.autosize=yes )
table(column=(type=char(4) updatewhereclause=yes name=type dbname="pipes.type" )
column=(type=datetime updatewhereclause=yes name=date_of_change dbname="pipes.date_of_change" )
column=(type=long updatewhereclause=yes name=change_of_length dbname="pipes.change_of_length" )
retrieve="SELECT type, installed as date_of_change, length change_of_length
from pipes
where (installed BETWEEN :date_start AND :date_end) OR
((installed < :date_start) AND (isnull (removed, :date_end) >= :date_start))
union all
select type, isnull (removed, dateadd (day, 1, :date_end)), (length * -1)
from pipes
where (installed BETWEEN :date_start AND :date_end) OR
((installed < :date_start) AND (isnull (removed, :date_end) >= :date_start))
order by date_of_change, type" filter=" date_of_change <= date_end "arguments=(("date_start", date),("date_end", date)) sort="type A date_of_change A " )
group(level=1 header.height=76 trailer.height=0 by=("type" ) header.color="536870912" header.transparency="0" header.gradient.color="8421504" header.gradient.transparency="0" header.gradient.angle="0" header.brushmode="0" header.gradient.repetition.mode="0" header.gradient.repetition.count="0" header.gradient.repetition.length="100" header.gradient.focus="0" header.gradient.scale="100" header.gradient.spread="100" trailer.color="536870912" trailer.transparency="0" trailer.gradient.color="8421504" trailer.gradient.transparency="0" trailer.gradient.angle="0" trailer.brushmode="0" trailer.gradient.repetition.mode="0" trailer.gradient.repetition.count="0" trailer.gradient.repetition.length="100" trailer.gradient.focus="0" trailer.gradient.scale="100" trailer.gradient.spread="100" )
text(band=header alignment="2" text="Type" border="0" color="33554432" x="5" y="4" height="64" width="224" html.valueishtml="0" name=type_t visible="1" font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
text(band=header alignment="2" text="From" border="0" color="33554432" x="334" y="4" height="64" width="137" html.valueishtml="0" name=t_1 visible="1" font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
text(band=header alignment="2" text="To" border="0" color="33554432" x="814" y="0" height="64" width="96" html.valueishtml="0" name=t_2 visible="1" font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
column(band=header.1 id=1 alignment="0" tabsequence=32766 border="0" color="33554432" x="9" y="0" height="64" width="224" format="[general]" html.valueishtml="0" name=type visible="1" edit.limit=4 edit.case=any edit.autoselect=yes edit.autohscroll=yes font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
compute(band=detail alignment="0" expression="if (type = type[1] and getrow() < rowcount() and date_of_change[1] <= date_end, RelativeDate(date_of_change[1], -1), date_end )"border="0" color="33554432" x="837" y="0" height="64" width="347" format="[SHORTDATE]" html.valueishtml="0" name=date_to visible="1~tif (date_of_change = date_of_change [1] and type = type[1], 0, 1)" resizeable=1 font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" height.autosize=yes)
compute(band=detail alignment="0" expression="cumulativesum ( change_of_length FOR GROUP 1)"border="0" color="33554432" x="1417" y="0" height="64" width="215" format="[GENERAL]" html.valueishtml="0" name=installed_length visible="1~tif (date_of_change = date_of_change [1] and type = type[1], 0, 1)" resizeable=1 font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" height.autosize=yes)
compute(band=detail alignment="0" expression="if (date_of_change < date_start, date_start, date_of_change)"border="0" color="33554432" x="320" y="8" height="64" width="311" format="[SHORTDATE]" html.valueishtml="0" name=date_from visible="1~tif (date_of_change = date_of_change [1] and type = type[1], 0, 1)" resizeable=1 font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" height.autosize=yes)
column(band=detail id=2 alignment="0" tabsequence=32766 border="0" color="33554432" x="1915" y="8" height="64" width="352" format="[shortdate]" html.valueishtml="0" name=date_of_change visible="0" resizeable=1 height.autosize=yes edit.limit=0 edit.case=any edit.autoselect=yes edit.autohscroll=yes font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
column(band=detail id=3 alignment="1" tabsequence=32766 border="0" color="33554432" x="2304" y="8" height="64" width="288" format="[General]" html.valueishtml="0" name=change_of_length visible="0" resizeable=1 height.autosize=yes edit.limit=0 edit.case=any edit.autoselect=yes edit.autohscroll=yes font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="536870912" background.transparency="0" background.gradient.color="8421504" background.gradient.transparency="0" background.gradient.angle="0" background.brushmode="0" background.gradient.repetition.mode="0" background.gradient.repetition.count="0" background.gradient.repetition.length="100" background.gradient.focus="0" background.gradient.scale="100" background.gradient.spread="100" tooltip.backcolor="134217752" tooltip.delay.initial="0" tooltip.delay.visible="32000" tooltip.enabled="0" tooltip.hasclosebutton="0" tooltip.icon="0" tooltip.isbubble="0" tooltip.maxwidth="0" tooltip.textcolor="134217751" tooltip.transparency="0" transparency="0" )
htmltable(border="1" )
htmlgen(clientevents="1" clientvalidation="1" clientcomputedfields="1" clientformatting="0" clientscriptable="0" generatejavascript="1" encodeselflinkargs="1" netscapelayers="0" pagingmethod=0 generatedddwframes="1" )
xhtmlgen() cssgen(sessionspecific="0" )
xmlgen(inline="0" )
xsltgen()
jsgen()
export.xml(headgroups="1" includewhitespace="0" metadatatype=0 savemetadata=0 )
import.xml()
export.pdf(method=0 distill.custompostscript="0" xslfop.print="0" )
export.xhtml()
Do you mean that in February (your dates are in DDMMYYY format) the length for PT1 should be a negative number, so that if you were to run the report for the first quarter of the year, the 2000 feet removed in February would be subtracted from the 2400 feet of PT1 installed in January, for a net installed length of 400 feet for PT1 over the quarter? If so, you could do this as the intersection of two inline or persistent views, one for the installs one for the removals, type and (extracted) time period being the join columns, subtracting removed length per type per period from installed length per type per period to get the net installed length per type per period. A left join between installs and removals.
If you also needed to track the removal of pipe that wasn't necessarily installed by your company -- e.g. there's a record of PT77 being removed but no record of PT77 being installed, you could address this as the UNION of two inline or persistent views, one for installs, one for removals, the removals being cast to negative lengths; then you would make that UNION ALL query itself into an inline view, where you'd group by type by period and sum the length.
Your sample result doesn't seem to make sense. This
Type From To Length
PT2 01/02/2011 28/02/2011 4000
PT1 01/02/2011 14/02/2011 2400
PT1 14/02/2011 24/02/2011 4400
PT1 25/02/2011 28/02/2011 2400
doesn't show how much PT1 pipe was installed for either January or February.
The following query shows the total length of pipe that was installed each month, one row per type.
select type,
extract(year from installed) || '-' || extract(month from installed) as year_month,
sum(length)
from pipes
group by type, year_month
order by year_month, type
returns
PT1 2011-1 2400
PT2 2011-1 4000
PT1 2011-2 2000
Later . . .
For the total length of pipe on any given date, I'd probably use something like this.
select p.type,
'2011-02-28' as effective_date,
(select sum(length)
from pipes
where installed <= '2011-02-28'
and type = p.type) as installed,
(select sum(length)
from pipes
where removed <= '2011-02-28'
and type = p.type) as removed
from pipes p
group by p.type, effective_date
order by type
That query returns
type effective_date installed removed
PT1 2011-02-28 4400 2000
PT2 2011-02-28 4000
Related
As ClickHouse can run complex SQL efficiently, we now write hundred-lines-in-one SQL to get the real time analysis results(join lots of source table). And it brings a problem is that it's so hard to maintain and reuse.
And we are using mybatis to write the sql in our Java Application. We try to use Mybatis's global parameter to define some sql for reuse, but not helps a lot in such huge lines SQL.
Is there any way to avoid such long sql or make the sql more readable and make this work more engineerable?
<select id="brandAnalysis" resultType="java.util.HashMap">
SELECT gmvRank.id_code,
gmvRank.rank,
gmvRank.lastRank,
gmvRank.gmv as sale_money,
member.dealerMembers as dealer_turnover,
member.teamMembers,
case
when member.dealerMembers = 0 then 0
when member.teamMembers = 0 then 0
else member.dealerMembers/member.teamMembers end AS dealer_turnover_active
FROM (
SELECT id_code,
<choose>
<when test="monthQuarter == 3">
case
when max(`quarter`) = #{quarter} then argMax(${sqlRankField},`month`)
else null end as rank,
case
when max(`quarter`) = #{quarter} then argMax(${sqlGmvField},`month`)
else null end as gmv,
case
when min(`quarter`) = #{compareQuarter} then argMin(${sqlRankField},`month`)
else null end as lastRank
</when>
<otherwise>
case
when max(`month`) = #{month} then argMax(${sqlRankField},`month`)
else null end as rank,
case
when max(`month`) = #{month} then argMax(${sqlGmvField},`month`)
else null end as gmv,
case
when min(`month`) = #{compareMonth} then argMin(${sqlRankField},`month`)
else null end as lastRank
</otherwise>
</choose>
FROM
tengju.dws_crm_brand_analysis_rank_dd_m
<choose>
<when test="monthQuarter == 3">
PREWHERE quarter in (#{quarter},#{compareQuarter})
and insert_time in (
SELECT MAX(insert_time)
FROM tengju.dws_crm_brand_analysis_rank_dd_m
PREWHERE quarter in (#{quarter},#{compareQuarter})
GROUP BY quarter
)
</when>
<otherwise>
PREWHERE month in (#{month},#{compareMonth})
and insert_time in (
SELECT MAX(insert_time)
FROM tengju.dws_crm_brand_analysis_rank_dd_m
PREWHERE month in (#{month},#{compareMonth})
GROUP BY month
)
</otherwise>
</choose>
<if test="dominationIdCode != null and dominationLevel != null">
and id_code in (
SELECT id_code
FROM tengju.dwd_user_domination_relation_map_all
PREWHERE visit_date >= formatDateTime(yesterday(),'%F')
AND insert_time in (
SELECT max(insert_time)
FROM tengju.dwd_user_domination_relation_map_all
PREWHERE visit_date >= formatDateTime(yesterday(),'%F')
)
AND domination_star_level = #{dominationLevel}
AND domination_id_code = #{dominationIdCode}
<if test="starLevels != null and starLevels.size() > 0">
AND star_level in
<foreach collection="starLevels" item="item" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
</if>
<if test="isDirect != null and isDirect > 0">
AND parent_id_code = #{dominationIdCode}
</if>
)
</if>
<if test="idCodes != null and idCodes.size() > 0">
AND id_code in
<foreach collection="idCodes" item="item" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
</if>
AND brand_id = #{brandId}
GROUP BY id_code
) as gmvRank
GLOBAL LEFT JOIN (
<choose>
<when test="crmRankCrowdPerspective == 4">
<include refid="smallTeamDealer" />
</when>
<when test="crmRankCrowdPerspective == 1">
<include refid="KATeamDealer" />
</when>
<otherwise>
<include refid="ecOrCityTeamDealer" />
</otherwise>
</choose>
) as member
on (gmvRank.id_code = member.id_code)
where 1=1
<if test="saleMoneyFrom != null">
AND gmvRank.gmv >= toDecimal128(#{saleMoneyFrom},2)
</if>
<if test="saleMoneyTo != null">
AND toDecimal128(#{saleMoneyTo},2) >= gmvRank.gmv
</if>
order by ${sortType}
LIMIT #{offset},#{pageSize}
</select>
User common table expressions to get rid of nested operations. Each make and version of database server has its own style of SQL. Not all have common table expressions. All have views though. SQL queries can be insanely verbose, for sure there is no other option.
I have below SQL stored procedure which generates a report and sends to me via email.
However it sends all the various rows as one big chunk report.
Rather I would want it to split each error
Any idea how I can split the below query to have individual XML reports generated.
DECLARE #Report XML
BEGIN
UPDATE [Orders].dbo.PurOrd
SET [Status] = 'Failed', Reason = '<e id="0" message="failed test order" />'
WHERE [Status] = 'InProcess'
SET #Report = (
SELECT
p.Name as "#Name",
p.Customer "#Customer",
CASE p.Name
WHEN 'Default' THEN convert(xml,p.RejectedReason)
ELSE convert(xml,f.RejectedReason)
END AS "RejectedReason",
(
SELECT u.first_name as "#FirstName",
u.last_name as "#LastName",
FROM [Users].dbo.Users u
WHERE u.user_id = u.user_id
for xml PATH('Users'), type
),
(
SELECT
li.Product as "#PId",
li.Quantity as "#Quantity",
li.SalePrice as "#Price",
FROM [Cart].dbo.LineItems li
WHERE li.OrderFormId = f.OrderFormId
ORDER BY li.ItemNumber
for xml PATH('LineItem'), type
)
FROM [Orders].dbo.OrForms f
JOIN [Orders].dbo.PurOrd p on f.GroupId = p.GroupId
WHERE
(p.Status = 'OrderRejected' AND p.ReportStatus IS NULL)
FOR XML PATH('test'), TYPE
)
SELECT #Report FOR XML PATH('Report')
Current Output:
<Report>
<PurchaseOrder OrderId="Order 1" Name="name1" Seller="abc">
<Reason>
<errors>
<e id="0" message="failed test ord" />
</errors>
</Reason>
<Users FirstName="abc" LastName="xyz"/>
<LineItem ProductId="Clothes1" Quantity="1.0000" SalePrice="100rs"/>
</PurchaseOrder>
<PurchaseOrder OrderId="Order 2" Name="name 2" Seller="abc">
<Reason>
<errors>
<e id="0" message="failed test ord" />
</errors>
</Reason>
<Users FirstName="abc" LastName="xyz"/>
<LineItem ProductId="Clothes1" Quantity="1.0000" SalePrice="100rs"/>
</PurchaseOrder>
</Report>
EXPECTED OUTPUT:
<Report>
<PurchaseOrder OrderId="Order 1" Name="name1" Seller="abc">
<Reason>
<errors>
<e id="0" message="failed test ord" />
</errors>
</Reason>
<Users FirstName="abc" LastName="xyz"/>
<LineItem ProductId="Clothes1" Quantity="1.0000" SalePrice="100rs"/>
</PurchaseOrder>
</Report>
<Report>
<PurchaseOrder OrderId="Order 2" Name="name 2" Seller="abc">
<Reason>
<errors>
<e id="0" message="failed test ord" />
</errors>
</Reason>
<Users FirstName="abc" LastName="xyz"/>
<LineItem ProductId="Clothes1" Quantity="1.0000" SalePrice="100rs"/>
</PurchaseOrder>
</Report>
One way to get
<Report>
<PurchaseOrder ... >
...
</PurchaseOrder>
</Report>
<Report>
<PurchaseOrder ...>
...
</PurchaseOrder>
</Report>
structure is to wrap your select list into CROSS APLLY. Kind of
SELECT t.PurchaseOrder
FROM [Orders].dbo.OrForms f
JOIN [Orders].dbo.PurOrd p on f.GroupId = p.GroupId
CROSS APPLY (
SELECT
-- original select list copy
p.Name as "#Name",
p.Customer "#Customer",
CASE p.Name
WHEN 'Default' THEN convert(xml,p.RejectedReason)
ELSE convert(xml,f.RejectedReason)
END AS "RejectedReason",
(
SELECT u.first_name as "#FirstName",
u.last_name as "#LastName",
FROM [Users].dbo.Users u
WHERE u.user_id = u.user_id
for xml PATH('Users'), type
),
(
SELECT
li.Product as "#PId",
li.Quantity as "#Quantity",
li.SalePrice as "#Price",
FROM [Cart].dbo.LineItems li
WHERE li.OrderFormId = f.OrderFormId
ORDER BY li.ItemNumber
for xml PATH('LineItem'), type
)
-- original select list copy END
FOR XML PATH(''), TYPE
) t(PurchaseOrder)
WHERE
(p.Status = 'OrderRejected' AND p.ReportStatus IS NULL)
FOR XML PATH('Report'), TYPE;
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
The purpose of this is to extract list of field names from the XML (of Adobe LiveCycle Designer). So, I created the fields in designer, then, I copy the XML of the related fields, paste in Notepad++, and then executer find/replace (ctrl-h) to get only the field names, one field in each line.
This will make it then easier to write the SQL statements to add such fields to the DB to register them.
The XML looks like the following:
<field xmlns="http://www.xfa.org/schema/xfa-template/2.8/" y="0in" x="0.343mm" w="8.881pt" h="9.108pt" name="detcon_recreation_only">
<ui>
<checkButton size="8.881pt">
<border>
<edge stroke="lowered"/>
<fill/>
</border>
</checkButton>
</ui>
<font size="0pt" typeface="Adobe Pi Std"/>
<para vAlign="middle"/>
<value>
<text>0</text>
</value>
<items>
<text>1</text>
<text>0</text>
<text/>
</items>
</field>
<field xmlns="http://www.xfa.org/schema/xfa-template/2.8/" name="detcon_special_housing" y="5.393mm" w="27.94mm" h="4.134mm" x="0.343mm">
<ui>
<choiceList>
<border>
<edge stroke="lowered"/>
</border>
<margin/>
</choiceList>
</ui>
<font typeface="Arial Narrow" size="6pt"/>
<margin topInset="0mm" bottomInset="0mm" leftInset="0mm" rightInset="0mm"/>
<para vAlign="middle"/>
<value>
<text>NA</text>
</value>
<items>
<text>Not Applicable</text>
<text>Hotel Component</text>
</items>
<items save="1" presence="hidden">
<text>NA</text>
<text>HC</text>
</items>
</field>
<exclGroup xmlns="http://www.xfa.org/schema/xfa-template/2.8/" name="detcon_photo_taken" x="0in" y="0in">
<?templateDesigner itemValuesSpecified 1?>
<field w="12.446mm" h="3.825mm" name="lb_yes">
<ui>
<checkButton size="1.7639mm" shape="round">
<border>
<?templateDesigner StyleID apcb1?>
<edge/>
<fill/>
</border>
</checkButton>
</ui>
<font typeface="Myriad Pro"/>
<margin leftInset="1mm" rightInset="1mm"/>
<para vAlign="middle"/>
<caption placement="right" reserve="7.698mm">
<para vAlign="middle" spaceAbove="0pt" spaceBelow="0pt" textIndent="0pt" marginLeft="0pt" marginRight="0pt"/>
<font size="8pt" typeface="Arial Narrow" baselineShift="0pt"/>
<value>
<text>YES</text>
</value>
</caption>
<value>
<text xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</value>
<items>
<text>1</text>
</items>
</field>
<field w="28.702mm" h="3.825mm" name="lb_no" x="13.233mm">
<ui>
<checkButton size="1.7639mm" shape="round">
<border>
<?templateDesigner StyleID apcb1?>
<edge/>
<fill/>
</border>
</checkButton>
</ui>
<font typeface="Myriad Pro"/>
<margin leftInset="1mm" rightInset="1mm"/>
<para vAlign="middle"/>
<caption placement="right" reserve="23.954mm">
<para vAlign="middle" spaceAbove="0pt" spaceBelow="0pt" textIndent="0pt" marginLeft="0pt" marginRight="0pt"/>
<font size="8pt" typeface="Arial Narrow" baselineShift="0pt"/>
<value>
<text>NO (see comments)</text>
</value>
</caption>
<value>
<text xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</value>
<items>
<text>0</text>
</items>
</field>
<border>
<edge presence="hidden"/>
</border>
<?templateDesigner expand 1?></exclGroup>
So I figured out the following RegEx to perform find/replace to get only the field names, one field on each line.
Find to get Field Name: (?i)<(field|exclGroup).*name="([a-z_]\w*)".*$
Replace: $2
Another find/replace...
Remove all other lines: ^.*<(?!.*name=).*.*[\r\n]*
Replace with blank
If you execute the above two find/replace sessions, you will end up with list of field names one field per line.
What I wanted to do is to perform the above in one find/replace session, and then convert the above into SQL Statements using also find/replace, using this template:
INSERT INTO table_name (element_id, element_name, element_type, default_value, required, clone)
VALUES (12345,"field_name_goes_here","/Tx", "", "N", "Y"),
VALUES (12346,"field_name_goes_here","/Tx", "", "N", "Y"),
VALUES (12347,"field_name_goes_here","/Tx", "", "N", "Y"),
VALUES (12348,"field_name_goes_here","/Tx", "", "N", "Y"),
VALUES (12349,"field_name_goes_here","/Tx", "", "N", "Y"),
The element_id field is sequential, but don't worry about that, I can take care of this in Excel.
Appreciate your help,
Tarek
Scraper Series
One small help. The element is slightly different than the which is making things a little more complicated. Your RegEx is so sophisticated, I couldn't modify it to include the element. I think I need more time to digest it. So could you modify it to include exclGroup and only extract name only without extracting the inner field elements of the exclGroup?
Ok, here you go.
It does make it a little more complicated.
I have 2 versions to do this. One that uses recursion, one that doesn't.
I'm posting the version that uses recursion.
If you need the non-recursion, let me know and I'll post that.
Find (?:(?!<(?:field|exclGroup)(?!\w)(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+>)[\S\s])*(?><(field|exclGroup)(?=(?:[^>"']|"[^"]*"|'[^']*')*?\sname\s*=\s*(?:(['"])([\S\s]*?)\2))\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+>)(?:(?&core)|)</\1\s*>(?:(?!<(?:field|exclGroup)(?!\w)(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+>)[\S\s])*(?(DEFINE)(?<core>(?>(?><([\w:]+)(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+>)(?:(?&core)|)</\5\s*>|(?!</[\w:]+\s*>)(?>[\S\s]))+))
Replace VALUES (12345,"$3","/Tx", "", "N", "Y"),\r\n
https://regex101.com/r/icnF3i/1
Formatted (incase you need to look at it)
(?: # Prefix - Optional any chars that don't start a field or exclGroup tag
(?!
<
(?: field | exclGroup )
(?! \w )
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
>
)
[\S\s]
)*
(?> # open 'field' or 'exclGroup' tag ------------------
<
( field | exclGroup ) # (1)
(?= # Asserttion (a pseudo atomic group)
(?: [^>"'] | " [^"]* " | ' [^']* ' )*?
\s name \s* = \s*
(?:
( ['"] ) # (2), Quote
( [\S\s]*? ) # (3), Name value - only thing we want
\2
)
)
\s+
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
>
)
(?:
(?&core) # Call the core recursion function (balanced tags)
|
)
</ \1 \s* > # Close 'field' or 'exclGroup' tag ------------------
(?: # Postfix - Optional any chars that don't start a field or exclGroup tag
(?!
<
(?: field | exclGroup )
(?! \w )
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
>
)
[\S\s]
)*
# ---------------------------------------------------------
(?(DEFINE)
(?<core> # (4 start), Inner balanced tags
(?>
(?>
<
( [\w:]+ ) # (5), Any open tag
(?>
" [\S\s]*? "
| ' [\S\s]*? '
| (?:
(?! /> )
[^>]
)?
)+
>
)
(?: # Recurse core
(?&core)
|
)
</ \5 \s* > # Balanced close tag (I can see you 5)
|
(?! </ [\w:]+ \s* > ) # Any char not starting a close tag (passive)
(?> [\S\s] )
)+
) # (4 end)
)
You can view the non-recursive version here https://regex101.com/r/ztOrP5/1
I am trying to simplify the RegEx provided in the previous answer.
This is my simplified version:
RegEx: (?|(?><field.*name\s*=\s*"([a-z_]\w*)"(?:.|\n)*?(?:<\/field>))|(?:<exclGroup.*name\s*=\s*"([a-z_]\w*)"(?:.|\n)*?(?:<\/exclGroup>)))
Replace: $1
Check it out over here: https://regex101.com/r/icnF3i/3
Appreciate your feedback.
Thanks to sln for helping me to reach this level.
EDIT:
The above RegEx doesn't work in Notepad++.
To use the same under Notepad++ use the following find/replace combination:
Find: (?i)<(field|exclGroup).*name\s*=\s*"([a-z_]\w*)"[\s\S]*?<\/\1>
Replace: \(12345,"$2","/Tx", "", "N", "Y"\),
Given is the value of "my_xml" column in "XYZ" table
<?xml version="1.0" encoding="UTF-8"?>
<India>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>GNR</string>
<string>Gandhinagar</string>
</city>
<city>
<string>PUN</string>
<string>Pune</string>
</city>
<city>
<string>RJT</string>
<string>Rajkot</string>
</city>
</India>
I am trying to extract value of second string node where first string node value is ADI
Output should be "Ahmedabad" only
Failed attempts:
select t.my_xml.extract('/India/city/string[2]/text()').getStringVal() from XYZ t where t.my_xml.existsNode('/India/city[string[1] = "ADI"]') = 1;
Output for above query is AhmedabadGandhinagarPuneRajkot
Expected output: Ahmedabad
How to extract specific node value for string node here?
You want to select the node that has the ADI text as first string.
Try this:
select
t.my_xml.extract('//city[./string[1]/text() = "ADI"]/string[2]/text()').getStringVal()
from XYZ t
where t.my_xml.existsNode('/India/city[string[1] = "ADI"]') = 1;
Use XMLTable to extract the values:
SELECT t.*
FROM XYZ x,
XMLTable(
'/India/city'
PASSING x.my_xml
COLUMNS string1 CHAR(3) PATH './string[1]',
string2 VARCHAR2(20) PATH './string[2]'
) t
WHERE t.string1 = 'ADI';
1) With xmlquery and flwor xquery
select xmlcast( xmlquery('for $i in ./India/city where $i//string[1]/text() = $cond return $i/string[2]/text()' passing xmltype(q'~<India>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>GNR</string>
<string>Gandhinagar</string>
</city>
<city>
<string>PUN</string>
<string>Pune</string>
</city>
<city>
<string>RJT</string>
<string>Rajkot</string>
</city>
</India>~'), 'ADI' as "cond" returning content) as varchar2(20)) result from dual;
2) If you're expecting more than one row try xmltable.
select * from xmltable('$doc/India/city' passing xmltype(q'~<India>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>GNR</string>
<string>Gandhinagar</string>
</city>
<city>
<string>PUN</string>
<string>Pune</string>
</city>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>RJT</string>
<string>Rajkot</string>
</city>
</India>~') as "doc"
columns
string1 varchar2(20) path'./string[1]/text()'
, string2 varchar2(20) path'./string[2]/text()'
)
where string1='ADI'
and xmltable with flwor xquery
select column_value from xmltable('for $el in $doc/India/city where $el//string[1]/text() = "ADI" return $el/string[2]/text()' passing xmltype(q'~<India>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>GNR</string>
<string>Gandhinagar</string>
</city>
<city>
<string>PUN</string>
<string>Pune</string>
</city>
<city>
<string>ADI</string>
<string>Ahmedabad</string>
</city>
<city>
<string>RJT</string>
<string>Rajkot</string>
</city>
</India>~') as "doc" )
;