consolidate rows in sql not working as it should - sql

I am having this issue with making consolidate for rows, I have made the query, but the result aren't correct.
It may consolidate the rows but for some result it will divide them into two different rows , what i need is to make them all in one row only if the id
is matching.
And here is the query :
Select
trxTransactionSaleItem.TransactionKey
, 'Sale' As TrxnType
, InvProduct.Id
, InvProduct.UPC
, trxTransactionSaleItem.Description
, invproduct.Description2
, invProduct.ProductGroupKey
, sum (Quantity/ISNULL(UOMBaseQuantity,1)) as Quantity
, Price
, SUM(DiscountAmount) AS DA
, SUM(SurchargeTotal) AS ST
, sum (Total) as Total
, ISNULL(UOM.Description,'') as UOM
From
trxTransactionSaleItem
INNER JOIN
InvProduct on trxTransactionSaleItem.ProductKey = InvProduct.ProductKey
LEFT JOIN
InvUOMGroupDetail UOMD on UOMGroupDetailKey = UOMD.UOMGroupDetailKey
LEFT JOIN
InvUOM UOM on UOMD.UOMKey = UOM.UOMKey
Where
Type = 0
And IsExchange = 0
And trxTransactionSaleItem.TransactionKey = 60000000022537
group by
trxTransactionSaleItem.TransactionKey
, InvProduct.Id
, InvProduct.UPC
, trxTransactionSaleItem.Description
, invproduct.Description2
, invProduct.ProductGroupKey
, Quantity
, Price
, DiscountAmount
, SurchargeTotal
, Total
, UOM.Description
So why its not coming in one row ?

Your group by should have only the fields that are not in aggregation functions. It should look like:
group by trxTransactionSaleItem.TransactionKey,
InvProduct.Id,
InvProduct.UPC,
trxTransactionSaleItem.Description,
invproduct.Description2,
invProduct.ProductGroupKey,
Price,
ISNULL(UOM.Description, '')

Related

How to calculate row using different value from joined table

I need to run an update on a SQL table, using a value from a different (but almost identical) row in the same table, to show how different sales scenarios play out.
e.g.
Starting with:
ITEM, SITE, SUPPLIER, SCENARIO, SALES_VOLUME, PRICE, TOTAL_SALES
1 , A , X , S1 , 100 , 10 , 1000
2 , A , Y , S1 , 25 , 20 , 500
1 , A , X , S2 , {blank} , 20 , 0
I would like to update to show:
ITEM, SITE, SUPPLIER, SCENARIO, SALES_VOLUME, PRICE, TOTAL_SALES
1 , A , X , 1 , 100 , 10 , 1000
2 , A , Y , 1 , 25 , 20 , 500
1 , A , X , 2 , {blank} , 20 , 2000
So basically, if SCENARIO = S2, I need to recalculate using SALES_VOLUME where SCENARIO = S1
I tried the following, but it didn't work - I think because I'm trying to specify both =1 and !=1 in the same lookup.
UPDATE TABLE1
SET [TOTAL_SALES] = (t1.[PRICE] * t2.[SALES_VOLUME])
FROM TABLE1 t1
inner join TABLE1 t2
on t1.[ITEM] = t2.[ITEM]
and t1.[SITE] = t2.[SITE]
and t1.[SUPPLIER] = t2.[SUPPLIER]
and t1.[SCENARIO] = 'S1'
WHERE t1.[SCENARIO] != 'S1'
I don't think I'm too far off, but just feel I'm missing something.
Any pointers would be gratefully received. :)
You may try this -
UPDATE t1
SET [TOTAL_SALES] = (t1.[PRICE] * t2.[SALES_VOLUME])
FROM TABLE1 t1
inner join TABLE1 t2
on t1.[ITEM] = t2.[ITEM]
and t1.[SITE] = t2.[SITE]
and t1.[SUPPLIER] = t2.[SUPPLIER]
and t1.[SCENARIO] = 'S2'
WHERE t2.[SCENARIO] = 'S1';

Group by - Non-group-by expression in select clause

Sorry you will have to bear with me as i am relativly new to SQL. I am querying an ODBC in EXCEL. At the moment my dataset is massive so i am looking to narrow it down by grouping it by company name and date. not all my columns are calculated fields.I have put the Sum on the two i need adding up. When i try to return the data i get the error of Non-group-by expression in select clause
Please can someone help me out.
SELECT
SopOrder_0.SooOrderNumber
, Company_0.CoaCompanyName
, InvoiceCreditItem_0.InvoiceCreditItemID
, InvoiceCreditItem_0.IciInvoiceApproved
, InvoiceCreditItem_0.InvoiceCreditID
, InvoiceCreditItem_0.CompanySiteID
, InvoiceCreditItem_0.VatID
, InvoiceCreditItem_0.NominalID
, InvoiceCreditItem_0.IciCreatedDate
, Sum(InvoiceCreditItem_0.IciTotalNettValue)
, Sum(InvoiceCreditItem_0.IciVatValue)
FROM
SBS.PUB.Company Company_0
, SBS.PUB.Customer Customer_0
, SBS.PUB.InvoiceCreditItem InvoiceCreditItem_0
, SBS.PUB.SopOrder SopOrder_0
WHERE
SopOrder_0.SopOrderID = InvoiceCreditItem_0.SopOrderID
AND InvoiceCreditItem_0.CompanyID = Customer_0.CompanyID
AND InvoiceCreditItem_0.CompanyID = Company_0.CompanyID
AND (Company_0.CoaCompanyName<>'ATOS')
AND InvoiceCreditItem_0.IciCreatedDate >= ?
GROUP BY
Company_0.CoaCompanyName, InvoiceCreditItem_0.IciCreatedDate

SQL Server Select one column by aggregate but not another

Not good with sql. Forgive me if the question isn't 100% clear. Here is my query
SELECT
MAX(PatientId),
[Date],
[Time],
CASE WHEN MAX(CAST(HealthScoreSkipped as INT)) = 1
THEN '--'
ELSE MAX(DailyHealthScore)
END DailyHealthScore,
ProtocolGroupName,
MAX(BloodPressure) BloodPressure,
MAX(SystolicAlert) SystolicAlert,
MAX(DiastolicAlert) DiastolicAlert,
MAX(BloodPressureSkipped) BloodPressureSkipped,
MAX(Pulse) Pulse,
MAX(PulseAlert) PulseAlert,
MAX(PulseSkipped) PulseSkipped,
MAX(BloodSugar) BloodSugar,
MAX(BloodSugarAlert) BloodSugarAlert,
MAX(BloodSugarSkipped) BloodSugarSkipped,
MAX(Steps) Steps,
MAX(StepsAlert) StepsAlert,
MAX(StepsSkipped) StepsSkipped,
MAX(O2) O2,
MAX(O2Alert) O2Alert,
MAX(O2Skipped) O2Skipped,
MAX(Weight) Weight,
MAX(WeightAlert) WeightAlert,
#BaselineWeight AS BaselineWeight,
MAX(WeightSkipped) WeightSkipped,
MAX(Temperature) Temperature,
MAX(TemperatureAlert) TemperatureAlert,
MAX(TemperatureUnit) TemperatureUnit,
MAX(TemperatureSkipped) TemperatureSkipped,
MAX(PEF) PEF,
MAX(PEFAlert) PEFAlert,
MAX(PEFSkipped) PEFSkipped,
MAX(FEV1) FEV1,
MAX(FEV1Alert) FEV1Alert,
MAX(FEV1Skipped) FEV1Skipped,
MAX(FEVRatio) FEVRatio,
MAX(FEVRatioAlert) FEVRatioAlert,
MAX(FEVRatioSkipped) FEVRatioSkipped,
#SpiroEnabled SpiroEnabled
FROM #bioAndScores
GROUP BY PatientId, Date, Time, ProtocolGroupName
The problem here is on the lines
MAX(Steps) Steps,
MAX(StepsAlert) StepsAlert
I want to select the max Steps but the stepalert value that goes with that row not the max of the stepAlert.
You can create a sub query in the select statement to get the steps alert that corresponds to your step.
something along the lines of the below (note that I'm not sure why you are grouping by patientId, if you are taking the max(patientId) if you do want to group by patient id, the where clause of the sub query should also match on patient Id
SELECT
MAX(bas.PatientId),
bas.[Date],
bas.[Time],
bas.ProtocolGroupName,
.
.
.
MAX(bas.Steps) Steps,
--sub query to get the StepsAlert that corresponds to max steps
(SELECT
StepsAlert
FROM
#bioAndScores subBas
WHERE
--This is the important part of finding the match for Max Steps
MAX(bas.Steps) = subBas.Steps AND
--commented out because the MAX(PatientId) was ambiguous
--bas.PatientId = subBas.PatientId AND
bas.[Date] = subBas.[Date] AND
bas.[Time] = subBas.[Time] AND
bas.ProtocolGroupName = subBas.ProtocolGroupName) as StepsAlert
FROM
#bioAndScores as bas
GROUP BY
--PatientId,
bas.Date,
bas.Time,
bas.ProtocolGroupName
Remove the MAX() function from StepAlerts and add StepAlerts to your GROUP BY clause.
MAX(Steps) AS Steps,
StepsAlert AS StepsAlert
And in your GROUP BY:
GROUP BY PatientId, Date, Time, ProtocolGroupName, StepAlerts
Just add StepsAlert column to the group by clause and remove the MAX aggregate function.
GROUP BY PatientId, Date, Time, ProtocolGroupName,StepsAlert
I would suggest you go through this to better understand about how group by works.
You can do this using apply() to select the set of values that correspond to the highest Steps at the earliest StepsAlert like so:
select
PatientId
, [Date]
, [Time]
, DailyHealthScore = case
when MAX(CAST(HealthScoreSkipped as int))= 1 then '--'
else MAX(DailyHealthScore)
end
, ProtocolGroupName
, BloodPressure = MAX(BloodPressure)
, SystolicAlert = MAX(SystolicAlert)
, DiastolicAlert = MAX(DiastolicAlert)
, BloodPressureSkipped= MAX(BloodPressureSkipped)
, Pulse = MAX(Pulse)
, PulseAlert = MAX(PulseAlert)
, PulseSkipped = MAX(PulseSkipped)
, BloodSugar = MAX(BloodSugar)
, BloodSugarAlert = MAX(BloodSugarAlert)
, BloodSugarSkipped = MAX(BloodSugarSkipped)
, Steps = x.Steps
, StepsAlert = x.StepsAlert
, StepsSkipped = MAX(StepsSkipped)
, O2 = MAX(O2)
, O2Alert = MAX(O2Alert)
, O2Skipped = MAX(O2Skipped)
, Weight = MAX(Weight)
, WeightAlert = MAX(WeightAlert)
, BaselineWeight = #BaselineWeight
, WeightSkipped = MAX(WeightSkipped)
, Temperature = MAX(Temperature)
, TemperatureAlert = MAX(TemperatureAlert)
, TemperatureUnit = MAX(TemperatureUnit)
, TemperatureSkipped = MAX(TemperatureSkipped)
, PEF = MAX(PEF)
, PEFAlert = MAX(PEFAlert)
, PEFSkipped = MAX(PEFSkipped)
, FEV1 = MAX(FEV1)
, FEV1Alert = MAX(FEV1Alert)
, FEV1Skipped = MAX(FEV1Skipped)
, FEVRatio = MAX(FEVRatio)
, FEVRatioAlert = MAX(FEVRatioAlert)
, FEVRatioSkipped = MAX(FEVRatioSkipped)
, SpiroEnabled = #SpiroEnabled
from #bioAndScores b
cross apply (
select top 1
i.Steps
, i.StepsAlert
from #bioAndScores i
where b.PatientId = i.PatientId
and b.[Date] = i.[Date]
and b.[Time] = i.[Time]
and b.ProtocolGroupName = i.ProtocolGroupName
order by i.Steps desc, i.StepsAlert asc
) x
group by
PatientId
, date
, time
, ProtocolGroupName

ORA-30926: unable to get a stable set of rows in the source tables

I have a customer who gets: ORA-30926: unable to get a stable set of rows in the source tables:
Log show error Massage Error (30926)
13:52:19 (00:00:02.406) ERROR : Error (30926) (00:00:02.406) ORA-30926: Stabile Zeilengruppe in den Quelltabellen kann nicht eingelesen werden
TS03_MIN0100: UpdTable failed. Update inv_value in cMinTimeTable:
MERGE INTO HUBWBPMS5_ENTTS03005400223 a USING ( SELECT DISTINCT a.inv_value +
( a.inv_value_sum - h.inv_value ) AS inv_value , a.rowid xzfd_rid
FROM HUBWBPMS5_ENTTS03005700223 h , HUBWBPMS5_ENTTS03005400223 a
WHERE a.voucher_no = h.voucher_no AND a.sequence_no = h.max_seq_no
AND a.client = h.client ) xzfd_t ON ( xzfd_t.xzfd_rid = a.rowid )
WHEN MATCHED THEN
UPDATE
SET a.inv_value = xzfd_t.inv_value
I have checked for duplicate values in the tables but cant find anything unusual.
Maybe someone has an idea that could be useful.
The query is:
Query causing error (temp table):
INSERT INTO HUBWBPMS5_ENTTS03005700228 ( agg_flag , ace_code , activity , category , client , cost_dep , description , dim1 , dim2 , dim3 , dim4 , inc_ref , inv_value , max_seq_no , pd , period , project , resource_id , resource_typ , trans_date , unit , voucher_no , work_order , work_type )
SELECT agg_flag , ace_code , activity , category , client , cost_dep , description , dim1 , dim2 , dim3 , dim4 , inc_ref , SUM ( inv_value ) inv_value , max_seq_no , pd , period , project , resource_id , resource_typ , trans_date , unit , voucher_no , work_order , work_type
FROM HUBWBPMS5_ENTTS03005400228
WHERE agg_flag = 1
GROUP BY agg_flag , ace_code , activity , category , client , cost_dep , description , dim1 , dim2 , dim3 , dim4 , period , trans_date , voucher_no , max_seq_no , inc_ref , pd , project , resource_id , resource_typ , unit , work_order , work_type
When you get that error, it will be from a MERGE statement, and it indicates that there are multiple rows in the source dataset that match to a row you're joining to in the target table, and as such, Oracle doesn't know which one to use to do the update.
Taking your merge statement:
MERGE INTO HUBWBPMS5_ENTTS03005400223 a
USING (SELECT DISTINCT a.inv_value + ( a.inv_value_sum - h.inv_value ) AS inv_value,
a.rowid xzfd_rid
FROM HUBWBPMS5_ENTTS03005700223 h,
HUBWBPMS5_ENTTS03005400223 a
WHERE a.voucher_no = h.voucher_no
AND a.sequence_no = h.max_seq_no
AND a.client = h.client) xzfd_t
ON (xzfd_t.xzfd_rid = a.rowid)
WHEN MATCHED THEN
UPDATE SET a.inv_value = xzfd_t.inv_value;
it looks like the join between the two tables HUBWBPMS5_ENTTS03005700223 and HUBWBPMS5_ENTTS03005400223 in the xzfd_t subquery causes multiple rows to be returned for one or more of the HUBWBPMS5_ENTTS03005400223 rows (ie. you get multiple rows returned for at least one a.rowid).
To check this, run:
SELECT xzfd_rid,
COUNT(*) cnt
FROM (SELECT DISTINCT a.inv_value + ( a.inv_value_sum - h.inv_value ) AS inv_value,
a.rowid xzfd_rid
FROM HUBWBPMS5_ENTTS03005700223 h,
HUBWBPMS5_ENTTS03005400223 a
WHERE a.voucher_no = h.voucher_no
AND a.sequence_no = h.max_seq_no
AND a.client = h.client)
GROUP BY xzfd_rid
HAVING COUNT(*) > 1;
In order to fix this, you'd need to make the xzfd_t subquery return a single row for each xzfd_rid. Possibly using row_number() to pick a single row, or an aggregate query to sum up all the h.inv_value fields per a.rowid instead of the DISTINCT.

speed up SQL Query

I have a query which is taking some serious time to execute on anything older than the past, say, hours worth of data. This is going to create a view which will be used for datamining, so the expectations are that it would be able to search back weeks or months of data and return in a reasonable amount of time (even a couple minutes is fine... I ran for a date range of 10/3/2011 12:00pm to 10/3/2011 1:00pm and it took 44 minutes!)
The problem is with the two LEFT OUTER JOINs in the bottom. When I take those out, it can run in about 10 seconds. However, those are the bread and butter of this query.
This is all coming from one table. The ONLY thing this query returns differently than the original table is the column xweb_range. xweb_range is a calculated field column (range) which will only use the values from [LO,LC,RO,RC]_Avg where their corresponding [LO,LC,RO,RC]_Sensor_Alarm = 0 (do not include in range calculation if sensor alarm = 1)
WITH Alarm (sub_id,
LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm) AS (
SELECT sub_id, LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm
FROM dbo.some_table
where sub_id <> '0'
)
, AddRowNumbers AS (
SELECT rowNumber = ROW_NUMBER() OVER (ORDER BY LO_Avg)
, sub_id
, LO_Avg, LO_Sensor_Alarm
, LC_Avg, LC_Sensor_Alarm
, RO_Avg, RO_Sensor_Alarm
, RC_Avg, RC_Sensor_Alarm
FROM Alarm
)
, UnPivotColumns AS (
SELECT rowNumber, value = LO_Avg FROM AddRowNumbers WHERE LO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, LC_Avg FROM AddRowNumbers WHERE LC_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RO_Avg FROM AddRowNumbers WHERE RO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RC_Avg FROM AddRowNumbers WHERE RC_Sensor_Alarm = 0
)
SELECT rowNumber.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
, COALESCE(range1.range, range2.range) AS xweb_range
FROM AddRowNumbers rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = MAX(value) - MIN(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) > 1) range1 ON range1.rowNumber = rowNumber.rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = AVG(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) = 1) range2 ON range2.rowNumber = rowNumber.rowNumber
INNER JOIN dbo.some_table cds
ON rowNumber.sub_id = cds.sub_id
It's difficult to understand exactly what your query is trying to do without knowing the domain. However, it seems to me like your query is simply trying to find, for each row in dbo.some_table where sub_id is not 0, the range of the following columns in the record (or, if only one matches, that single value):
LO_AVG when LO_SENSOR_ALARM=0
LC_AVG when LC_SENSOR_ALARM=0
RO_AVG when RO_SENSOR_ALARM=0
RC_AVG when RC_SENSOR_ALARM=0
You constructed this query assigning each row a sequential row number, unpivoted the _AVG columns along with their row number, computed the range aggregate grouping by row number and then joining back to the original records by row number. CTEs don't materialize results (nor are they indexed, as discussed in the comments). So each reference to AddRowNumbers is expensive, because ROW_NUMBER() OVER (ORDER BY LO_Avg) is a sort.
Instead of cutting this table up just to join it back together by row number, why not do something like:
SELECT cds.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
--if the COUNT is 0, xweb_range will be null (since MAX will be null), if it's 1, then use MAX, else use MAX - MIN (as per your example)
, (CASE WHEN stats.[Count] < 2 THEN stats.[MAX] ELSE stats.[MAX] - stats.[MIN] END) xweb_range
FROM dbo.some_table cds
--cross join on the following table derived from values in cds - it will always contain 1 record per row of cds
CROSS APPLY
(
SELECT COUNT(*), MIN(Value), MAX(Value)
FROM
(
--construct a table using the column values from cds we wish to aggregate
VALUES (LO_AVG, LO_SENSOR_ALARM),
(LC_AVG, LC_SENSOR_ALARM),
(RO_AVG, RO_SENSORALARM),
(RC_AVG, RC_SENSOR_ALARM)
) x (Value, Sensor_Alarm) --give a name to the columns for _AVG and _ALARM
WHERE Sensor_Alarm = 0 --filter our constructed table where _ALARM=0
) stats([Count], [Min], [Max]) --give our derived table and its columns some names
WHERE cds.sub_id <> '0' --this is a filter carried over from the first CTE in your example