How do I pivot dynamically - pivot

I have two tables; Leads, Territories and Referrers.
Lead has columns: ID, Name, TerritoryId
Referrers has: ID, LeadId, Name
Territory has: ID and Name
A lead always relates to a territory and a lead can optionally relate to a Referrer.
Leads and Referrer records are regularly inserted (Referrers less frequently). I want to output a report in a GridView which looks like this:
Territory | Lead Count | Ref1 Lead Count | Ref2 Lead Count | Ref3 Lead Count
Leeds 10 1 7 2
Exeter 43 9 21 8
etc...
OK, so the problem is, I want to group by Territory and Count the leads per territory.... this is fine:-
select t.Name, COUNT(1)
from Territory t inner join Lead l on l.TerritoryID = t.Id
group by t.Name
But now I want to break down count by referrer.
I understand I can do that partly with PIVOT, however, I understand that I have to explicitly state the Referrers in code. Is there any way to perform some kind of dynamic pivot which appends additional columns based on the number of rows in Referrer?
Would I have to use dynamic SQL inside an SP?

something like this:
select * from (select r.name, t.name as Territory
from referrers r join Lead l on l.Id = r.leadId
join Territory t on l. TerritoryID = t.Id) s
pivot(count(Name) for Name in ([geoff],[fred])) p
As far as I can see the referrers would have to be specified explicitly, so you would have to generate the square bracketed list in an sp if you wanted them to be dynamic.

Related

UOM and UOM ratio incorrect on Pick Ticket

We use UOM conversions at this client. We stock in Eaches and sell in Cases. The problem we are having with the Pick ticket is that both the quantity to be picked and the UOM being picked are the stocking unit and not the selling unit.
e.g. The customer orders 73 cases (12 ea per case). The pick ticket prints 876 each. This requires the warehouse person to look up each item determine if there is a Selling UOM and ratio and to then manually convert 876 eaches to 73 cases.
Obviously, the pick ticket should print 73 cases. But I cannot find a way to do this. The items are lotted and an order of 73 case might have 50 cases of Lot A and 23 cases of Lot B. This is represented in the SOShipLineSplit table. The quantities and UOM in this table are based on Stocking units.
Ideally, I could join the INUnits table to both the SOSHipLine and SOShipLineSPlit table. See Below.
Select case when isnull(U.UnitRate,0) = 0 then S.Qty else S.Qty/U.Unitrate end as ShipQty
,case when isnull(U.UnitRate,0) = 0 then s.uom else U.FromUnit end as UOM
from SOShipLineSplit S
inner join SOShipLine SL
ON S.CompanyID = SL.CompanyID and s.ShipmentNbr = SL.ShipmentNbr and S.LineNbr = SL.LineNbr and S.InventoryID = SL.InventoryID
Left Outer Join INUnit U
On S.CompanyID = U.CompanyID and S.InventoryID = U.InventoryID and s.UOm = U.ToUnit and SL.UOM = U.FromUnit
where S.ShipmentNbr = '000161' and S.CompanyId = 4
The problem is the Acumatica Report writer does not support a join with multiple tables.
Left Outer Join INUnit U
On S.CompanyID = U.CompanyID and S.InventoryID = U.InventoryID and s.UOm = U.ToUnit and SL.UOM = U.FromUnit
I believe I must be missing something. This cannot be the only client using Acumatica who utilizes Selling Units of Measure. Is there another table I could use that would contain the quantities and UOM already converted for this order to Selling Units?
Or another solution?
Thanks in advance.
pat
EDIT:
If the goal is to display accurate quantities before/after conversion then INUnit DAC can't be used. It doesn't store historical data, you can change INUnit values after an order has been finalized so re-using it to compute quantities will not yield accurate results.
For that scenario you would need to use the historical data fields with Base prefixes like ShippedQuantity/BaseShippedQuantity. If you require to store more historical data you need to add a custom field to hold these values and update them when shipment is created/modified.
The main issue appears to be a logical error in the requirement:
The problem is that the INUnit table has to be joined to BOTH the
SOShipLine and the SOShipLineSplit tables.
INUnit DAC has a single parent, not 2 so you need to change your requirement to reflect that constraint.
If SOShipLine and SOShipLineSplit values differ then you'll never get any record.
If they are identical then there's no need to join on both since they have the same value.
I suggest to add 2 joins, one for SOShipLine and another for SOShipLineSplit. In the report you can choose which one to display (1st, 2nd or both).
You can also add visibility conditions or IIF formula condition in the report if you want to handle null values error check for display purpose.
Use the Child Alias property in schema builder to join the same table 2 times without name conflicts. In the report formulas (to display field or in formula conditions) use the Child Alias table name too.
Example:

MsAccess Delete all values but one in column by condition

I have a table in MS ACCESS 2013 that looks like this:
Id Department Status FollowingDept ActualArea
1000 Thinkerers Thinking Thinkerer Thinkerer
1000 Drawers OnDrawBoard Drawers Drawers
1000 MaterialPlan To Plan MaterialPlan MaterialPlan
1000 Painters MatNeeded MaterialPlan
1000 Builders DrawsNeeded Drawers
The table gives follow to an ID which has to pass through five departments, each department with atleast 5 different status.
Each status has a FollowingDept value, like *Department* Thinkerers has the status MoreCoffeeNow which means *FollowingDept* Drawers.
All columns except for ActualArea are columns which values are gotten from the feed of a query.
ActualArea is an Expr where I inserted this logic:
Iif(FollowingDept = Department, FollowingDept, "")
My logic is simple, if the FollowingDept and Department coincide, then the ID's ActualArea gets the value from FollowingDept.
But as you can see, there can be rare cases where an ID is like my example above, where 3 departments coincide with the FollowingDept. This cases are rare, but I would like to add something like a priority to Access.
Thinkerers has the top priority, then MaterialPlan, then Drawers, then Builders and lastly Painters. So, following the same example, after ActualArea gets 3 values, Access will execute another query or subquery or whatever, where it will evaluate each value priority and only leave behind that one with the top priority. So in this example, Thinkerers gets the top priority, and the other two values are eliminated from the ActualArea column.
Please keep in mind there are over 500 different IDs, each id is repeated 5 times, so the total records to evaluate will be 2500.
You need another table, with the possible values for actualArea and the priorities as numbers, and then you can select with a JOIN and order on the priority:
SELECT TOP 1 d.*, p.priority
FROM departments d
LEFT JOIN priorities p ON d.actualArea = p.dept
WHERE d.id = 1000
AND p.priority IS NOT NULL
ORDER BY p.priority ASC
The IS NOT NULL clause eliminates all of the rows where actualArea is empty. The TOP condition leaves only the row with the top priority.
You don't seem to have a primary key for your table. If you don't, then I'll give another query in a minute, but I would strongly advise you to go back and add a primary key to the table. It will save you an incredible amount of headache later. I did add such a key to my test table, and it's called pID. This query makes use of that pID to remove the records you need:
DELETE FROM departments WHERE pID NOT IN (
SELECT TOP 1 d.pID
FROM departments d
LEFT JOIN priorities p ON d.actualArea = p.dept
WHERE id = 1000
AND p.priority IS NOT NULL
ORDER BY p.priority ASC
)
If you can't add a primary key to the data and actualArea is assumed to be unique, then you can just use the actualArea values to perform the delete:
DELETE FROM departments WHERE actualArea NOT IN (
SELECT TOP 1 d.actualArea
FROM departments d
LEFT JOIN priorities p ON d.actualArea = p.dept
WHERE id = 1000
AND p.priority IS NOT NULL
ORDER BY p.priority ASC
) AND id = 1000
If actualArea is not going to be unique, then we'll need to revisit this answer. This answer also assumes that you already have the id number.

Concatenate each column value into a string for a subquery

All I've done a lot of background reading on this on and off for the past day or so and I'm none the wiser on how to achieve this.
I have looked on this site and found ways of concatenating multiple rows into one column however what I'm after is a bit more bespoke, please help...
I have two tables - one is a list of people and details about them such as name etc and a person reference.
The second contains a number of alerts about a person, one person can have multiple alerts. This would contain a person reference and the type of alert they have in a string.
I want to join these two tables using an inner join on the person reference.
I next want to find all of the alerts for each person and concatenate it into a string and show this as the "All alerts" column.
So I will end up with the following output:
First Name | Surname | All Alerts
-----------+---------+--------------------------
Tony | Stark | Alert 1, Alert 2, Alert 3
I can get as far as going through all of the alerts in the alerts table and put the alerts for every person into a string, obviously I need a concatenated value for each person, and haven't figured out how to do this.
I've spent a day on this and looked into XMLPath solutions and using CTE, CROSS APPLY and subqueries to specify the where clause. I am a little lost.
DECLARE #ConcatenatedVals VARCHAR (255)
SET #ConcatenatedVals =
(
DECLARE #AllAlerts VARCHAR(8000)
SELECT #AllAlerts = COALESCE(#AllAlerts + ', ', '') + personAlert
FROM Alerts
SELECT #AllAlerts AS 'All Alerts'
)
I found the solution for this posted here:
https://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/#Toc205129480
This referenced a solution by Adam Machanic
Also, stuff is actually a function, not seen this before:
SELECT p1.CategoryId,
stuff( (SELECT ','+ProductName
FROM Northwind.dbo.Products p2
WHERE p2.CategoryId = p1.CategoryId
ORDER BY ProductName
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
,1,1,'')
AS Products
FROM Northwind.dbo.Products p1
GROUP BY CategoryId ;

How can I fetch 'distinct' data keeping row ID in the lookup view?

Assume I have an entity with the following structure:
ID (it would be the GUID of the record, I'll use number in this example for easier read)
Name
Product (lookup to product)
Price List (custom lookup to standard price list)
I now need to build a lookup view in this fashion:
(Sample data)
ID Name Product PriceList
-----------------------------------
1 Rec1 P1 PL1
2 Rec1 P1 PL2
3 Rec1 P1 PL3
4 Rec2 P2 PL1
5 Rec2 P2 PL2
(Desired result in lookup view)
ID Name
-----------------------------------
1 Rec1
4 Rec2
To explain the requirement in plain english, it is:
In the lookup view I only want one row per Name: Product and Price List don't matter.
Here's what I'd do if I could use straight T-SQL:
;WITH cte AS
(
SELECT ROW_NUMBER()
OVER (PARTITION BY Name ORDER BY Name ASC) AS RowNo, ID, Name
FROM FilteredEntity
)
SELECT ID, Name FROM cte WHERE RowNo = 1
But I can't figure out how to achieve the same result set in a FetchXML query.
The only way I can think of to do this would go like this:
In JS on your form, determine the unique names (Rec1 and Rec2 from your example), and store the ids of two records that reference Rec1 and Rec2 (let's call these ids Id1 and Id2)
Generate a fetch query that returns only those two records. Your fetch query would specifically say show me records where id is Id1 or Id2.
Filter the lookup using addCustomFilter and addPreSearch (link).
I can see two approaches here, neither of which are pure FetchXML queries.
Use distinct, (I'm not 100% on this but worth giving a go). This will then hopefully get you a record for every name, and you just grab the first record of each in code.
<attribute name='name' distinct='true'/>
Perform the filtering client side using Linq.

Excel - Power Query 2016

I got data from two tables.
Customers (containing customer ID and the total value of orders/funding
Orders (Containing customer ID and each order)
I created a Power Query, then chose the option to "Merge Queries as New". Selected the matching Columns (Customer ID) and chose the option:Left Outer (All from the first and, matching from second => All from the customer table, matching from the order table). Then I expanded the last column of the Query to include what I wanted from the Order table resulting in the table below on the left. The one on the right is what I'm after. The problem is that funding amounts are already totals per customer. I don't need the value of each order broken down. I still need the orders displayed but I don't need their values (just the total per customer). Is it possible to do it like the one below on the right? Otherwise, the grand total is way off.
I think what you're trying to do is join with only the first instance of each value in your Customer column. There doesn't appear to be any feature or GUI element that allows you to do that (I had a look at the reference documentation for Power Query M, maybe I missed something).
To replicate your data, I'm starting off with some tables (left table is namedCustomers, right table is namedOrders):
I then use the M code below (the first few lines are just to get my tables from the sheet):
let
customers = Excel.CurrentWorkbook(){[Name = "Customers"]}[Content],
orders = Excel.CurrentWorkbook(){[Name = "Orders"]}[Content],
merged = Table.NestedJoin(orders, {"CUSTOMER"}, customers, {"CUSTOMER"}, "merged", JoinKind.LeftOuter),
indexColumn = Table.AddIndexColumn(merged, "Temporary", 0, 1),
indexes =
let
uniqueCustomers = Table.Distinct(Table.SelectColumns(indexColumn, {"CUSTOMER"})), // Want to keep as table
listOfRecords = Table.ToRecords(uniqueCustomers),
firstOccurenceIndexes = List.Accumulate(listOfRecords, {}, (listState, currentItem) =>
List.Combine({listState, {Table.PositionOf(indexColumn, currentItem, Occurrence.First, "CUSTOMER")}})
)
in
firstOccurenceIndexes,
expandSelectively =
let
toBoolean = Table.TransformColumns(indexColumn, {{"Temporary", each List.Contains(indexes, _), type logical}}),
tableOrNull = Table.AddColumn(toBoolean, "toExpand", each if [Temporary] then [merged] else null),
dropRedundantColumns = Table.RemoveColumns(tableOrNull, {"merged", "Temporary"}),
expand = Table.ExpandTableColumn(dropRedundantColumns, "toExpand", {"FUNDING"})
in
expand
in
expandSelectively
If your table names and column names match mine (including case sensitivity), then you might just be able to copy-paste all of the M code above into the Advanced Editor and have it work for you. Otherwise, you may need to tweak as necessary.
This is what I get when I load the query to the worksheet.
There might be better (more efficient) ways of doing this, but this is what I have for now.
If you're not using the order ID column, then I would suggest doing a Group By on the OrderTable before merging in the funding so that you'd end up with a table like this instead:
Region Customer OrderCount Funding
South A 3 2394
South B 2 4323
South C 1 1234
South D 2 3423
This way you don't have mixed levels of granularity that cause problems like you are seeing with the totals.

Resources