Rendering a three level data hierarchy into an HTML table with ASP.NET - linq

Say I had some Airport, Aeroplane, Passenger and Seat classes in C#. Passenger has the id of an Aeroplane and Aeroplane has the id of an Airport. Passenger also has the id of a Seat.
How would I write a linq query to build them into a hierarchy then render them into an HTML table?
I need it to look some like:
1 2 3
Gatwick
747 July Kim Ben
767 Neal Toby
A380 Becky
Hong Kong
747 Gary Steve Gary
MiG-35 Ted
etc..
(Seat numbers are along the top)
I've been scratching my head in front of LinqPad for ages but I can only get one level in the hierarchy. I guess I may need to use nested GridViews or maybe write a custom control to render the resulting object but am not sure of the best approch.
Ideally I'd like to get all the data with a single query (a previous programmer has done it using one query per cell and the page takes a minute to load!)
Many thanks

This would require 2 LINQ queries:
You have to group by seat number (or get seat numbers using .Distinct()). Use this to output the columns;
Then group by airport, then airplane, then in each airplane grouping, you have the passengers - you .Join() them with your seats collection.
passengers
.GroupBy(p => p.Aeroplane)
.GroupBy(p => p.Airport)
.Join(seats, p=>p.Seat, s=>s, (p,s)=>new { Passenger = p, Seat = seat })
That will give you an array of passengers and their respective seat in each aeroplane and then in each airport.

Related

Advanced Filter on PowerQuery

Question
I am trying to filter some excel data I have on PowerQuery but am really struggling to figure out the best way to do this. On Excel I would usually do this using an Advanced Filter but I don't believe Power Query has the same functionality.
I would like to filter across a number of columns, using an OR condition for a:
a range of values in some columns; and
a range of 'wild card' searches in other columns
Example
As an example if my dataset is as below
Name
Function
Sub-Function
Position
Country
Andy
Sales
Omni-Channel
Sales Manager
Brazil
Bob
Marketing
eCommerce
Web Design
Argentina
Rakesh
HR
Business Partnering
HRBP
Italy
Tom
Finance
Reporting
Finance Manager
UK
Chris
Sales
Trade Marketing
Sales support
US
Raj
Legal
Legal
Para-legal
Brazil
I might want to filter for anyone meeting the following criteria;
working in the sales function OR
working in the Trade Marketing or Omni-Channel sub-function OR
has the words 'Manager' or 'Sales' in their Position title OR
is based in Brazil
The desired output would then be
Name
Function
Sub-Function
Position
Country
Andy
Sales
Omni-Channel
Sales Manager
Brazil
Tom
Finance
Reporting
Finance Manager
UK
Chris
Sales
Trade Marketing
Sales support
US
Raj
Legal
Legal
Para-legal
Brazil
My current approach
My approach was to create a table which had all my criteria (not including the 'wild card' searches), upload to PowerQuery, create multiple lists from this table (called for example Filter1, Filter2 etc..). Then using the following formula against my main dataset
= Table.SelectRows(#"Filtered Rows1", each (List.Contains(Filter1,[Function]) = true) or (List.Contains(Filter2,[Sub-Function]) = true) or (List.Contains(Filter3,[Country]) = true) or Text.Contains([Position], "Manager") or Text.Contains([Position], "Sales"))
Issues
The formula above works for really small data sets however not on my 80,000 line data set, or rather it does not work within a reasonable time frame
I have a long list of 'wild card' searches which apply to three columns so typing in the Text.Contain(...... etc.. formula multiple times into the formula seems very inefficient, is prone to mistakes and is not dynamic in any way.
I'm sure there must be a better way to do this but I have not found many helpful discussions or tutorials on this online so am reaching out to the community.
Thank you
I think the part of the problem the query is slow as with your current approach, filtering is evaluating filtering conditions separately before it could filter. Power bi is capable of handling filter on multiple columns in a single filter, like following
Table.SelectRows(
#"Changed Type1",
each ([Function] = "Sales")
or ([#"Sub-Function"] = "Trade Marketing" or [#"Sub-Function"] = "Omni-Channel")
or (
Text.Contains([Position], "Manager")
or Text.Contains([Position], "Sales")
or ([Country] = "Brazil")
)
)

In Dax, how can I get value from multiple columns with multiple criteria?

I am just a beginner in Dax language.
I googled it a lot to find solution, but failed.
Please help me to solve this problem.
Here are the two tables examples and there is no relation between them. ( I am using power query and power pivot)
I need to get sales location visitor from another table.
enter image description here
enter image description here
Branch
Date
Item
QTY
Sales Location
Visitor
USA.
2021.01.01
A.
23
1st floor
????
Canada
2021.01.02
B.
44
2nd floor
????
Date
USA's 1st floor visitor
USA's 2nd floor visitor
Canada's 1st floor visitor
Canada's 2nd floor visitor
2021.01.01
5435
664
2342
4532
2021.01.02
5345
345
2234
342
I tried to use IF and Lookupvalue, but it shows errors.
Could you please help me?
Thank you in advance.
You'll need to use Power Query to do some transformations to the second table so that it looks like this:
To do this, you'll have to transpose all columns, fill down the country column, and unpivot all other columns (highlight all other columns > unpivot columns). I'd then recommend adding a column to both tables that unites the country and sales location (USA-1st floor, USA-2nd floor, etc.) to both tables and use that as your connection in the model. You'll then be able to do a VLOOKUP using this united column between the tables.
Someone else may have a quicker answer but this should get you there!

Xpath query, making a certain query more generic

I'm trying to extract information from Wikipedia tables.
More specifically, I'm trying to make a list of all teams and all players in the premier league.
Until now I'm able to traverse over the whole teams in the premier league 2019-2020 table of teams, for every team there I get in it Wikipedia page and traverse over its player's getting their information.
I thought there is a fixed template that all premier league teams in Wikipedia have their table of players at position 3 but after traversing 6 teams it faced a team that it's table is in 2nd place.
So I was using the following XPath query on every team wiki page
"//table[3]/tbody//tr[position() > 1]//td[4]//span/a/#href"
but for example, the following team players table is at position 2, how can I make this query more generic and not fix it a certain position? I have noticed that all of my relevant tables have an element before it with the text "First-team squad"
The HTML of the table is too long, so I post here the wiki link of a certain team
https://en.wikipedia.org/wiki/Crystal_Palace_F.C.
Hope to get help! thanks.
You have to use another "anchor" which works for each page. The table you need is always the first after the span element "Players".
So with this :
//span[#id='Players']/following::table[1]//span[#class="fn"]//text()
You'll get the names of all players of the current squad team.
With this :
//span[#id='Players']/following::table[1]//span[#class="fn"]//#href
You'll get the associated URLs. /!\ Some players don't have a wikipedia webpage.
So you can have 26 player names but 25 urls. Like here :
https://en.wikipedia.org/wiki/Chelsea_F.C.

Unreliable results of a query

I need to get sales figures from open orders, sorted by code. The items are separated in the stock table by lot number (for traceability reasons) but the lot numbers do not appear in the orders table. The only link between the 2 tables is the part number.
When my query
SELECT code, SUM(qty*price) AS Sales
FROM orders INNER JOIN stock ON orders.partno = stock.partno
GROUP BY code
started returning strange results (very high sales figures for a given code), I changed it to
SELECT DISITNCT orders.partno, stock.lot, stock.code
FROM orders INNER JOIN stock ON orders.partno = stock.partno
and noticed that if several lots of a given part are in stock they are all returned
Part1 LotA code
Part1 LotB code
Part1 LotC code
which means that if a customer orders 300 units of Part1, my query returns 900 and my sales figure is multiplied by 3.
How can I work around that?
It must be noted that I do not work from a database but from a group of tables, the structures of which can sometimes be whimsical.
You should really use table.column or alias.column reference when writing queries. As your question stands, we do not know which table the PRICE comes from... the parts table or the lots table. If you are dealing with inventory tracking such as FIFO or LIFO method accounting, you must have an association to the lot table for inventory being tracked/sold.
Now, why are you getting large numbers? That is because of a Cartesian result. If you are not familiar with that, for each record in one table joined to another, it is returning however many matches.
So, if you have an order of one line item, there is only one line item in a products available table. So this is simple 1:1 ratio. Now, you have your STOCK table that can have multiple records for the exact same part number. You are now returning the same original order line item for EACH LOT ENTRY in the Stock table. So now, for your 1 item, you are getting 3 lots (1:3 result).
I know this is important from a cost-of-goods sold basis, hence your need to know which "lot" it is joined to so you only get that one specific record for proper pricing.
If however, you do have a generic product table of everything you sell, and that table has a generic common price no matter which "lot" was used for the sale, I would join to that table instead for your report. But you will still have the accounting issue of inventory, cost-of-goods, etc.

How to use LINQ (or TSQL) to group dataset but include top item and counts

I'm struggling with how to approach this. I have your basic dataset returned by a TSQL (SQL2005) query where the data contains a list of master and detail items. Pretty vanilla, you have your master table joined to your detail table so you might get mulitple rows back per master record.
Something like:
ID / Item Descr / Subitem Descr
1 / Jane Doe / shoes
1 / Jane Doe / hats
2 / John Smith / hats
What I'd like to get to do is "flatten" that out a bit. So something like:
ID / Item Descr / Count / Most Recent Subitem
1 / Jane Doe / 2 / shoes
2 / John Smith / 1 / hats
Any suggestions on the sql query, or perhaps a LINQ query that I could run on the dataset I get back from the initial sql query...?
var q = from i in Context.Items
group i by i.ItemDescr into g
select new
{
ID = g.FirstOrDefault().ID,
ItemDescr = g.Key,
Count = g.Count(),
MostRecentSubItem = g.FirstOrDefault().SubitemDescr // you don't show how to pick the "most recent"
};
Not quite sure what you mean by "top" but this is a start if you want to do it in SQL:
SELECT id, ItemDesc, COUNT(*), MAX(SubItemDesc)
FROM MyTable
GROUP BY id, ItemDesc
I ended up using a correlated sub-query, which always make me nervous from a performance perspective. I don't have numbers to back that up and am not great at reading Execution Plans, it's just a gut feeling.
Lot's of good stackoverflow examples on it that got me down that path(like: Advanced SQL query with sub queries, group by, count and sum functions in to SQLalchemy and Variant use of the GROUP BY clause in TSQL)
I was wondering if using any of the new windowing functions (row_number() or rank()) would have helped, but I didn't get very far down that line.
I still wonder if it would be better to just pull back all the master-detail rows, then "post process" them using LINQ would be better. Our SQL Server would throw back that dataset to the web server pretty darn fast, then "distribute" the work load by doing LINQ on the web server, finally binding it all up to my ASP.NET gridview and sending it the client. A lot of moving parts, but could be interesting...

Resources