MS Access Complex Query Help (Cross-Join typ) - sql

Greetings: I am working on a variant configurator for a part numbering system.
I have two tables which define the characteristics of the numbering system. Null means the combination is invalid and to be skipped.
Table 1:
PowerSize | Model A | Model B | Model... | Input A | Input B | Input... | Temp A | Temp B | Temp... |
20HP | S10 | S30 | null | 6P | null | 5R | 40C | 50C | null|
200HP |null|null| E10 | 6P | 3R | null | null | 50C | 55C|
**Table 2:**
Model | Normal Duty | Heavy Duty | Light Duty | No Filter | Sine Filter |
S10 | N | null | null | N | S |
S30 | null | H | null | N | null |
E10 | null | null | L | null | S |
I need a query (or series of queries) that explodes the valid combinations:
**Result Example**
**Model | PowerSize | Input | Temp | Duty | Filter |**
S10 | 20HP | 6P | 40C | N | N |
S10 | 20HP | 6P | 40C | N | S |
S10 | 20HP | 6P | 50C | N | N |
S10 | 20HP | 6P | 50C | N | S |
S10 | 20HP | 5R | 40C | N | N |
S10 | 20HP | 5R | 40C | N | S |
S10 | 20HP | 5R | 50C | N | N |
S10 | 20HP | 5R | 50C | N | S |
S30 | 20HP | 6P | 40C | H | N |
S30 | 20HP | 5R | 40C | H | N |
S30 | 20HP | 6P | 50C | H | N |
S30 | 20HP | 5R | 50C | H | N |
E10 | 200HP | 6P | 50C | L | S |
E10 | 200HP | 3R | 50C | L | S |
E10 | 200HP | 6P | 55C | L | S |
E10 | 200HP | 3R | 55C | L | S |
and so forth.
I tried using Dlookup but wasn't able to sort it out.
I tried DLookup but it didn't handle the null's as exclusions (at least I couldn't figure out how to do the criteria for it to work)
Can someone give me some pointers or examples? Greatly appreciated in advance.

use null check, example : Not IsNull(DLookup(

I built a VBA script using two loops to build a set of union queries based on a auxiliary table containing all fields, and then manually joined each union query to create the completed list (about 50,000 lines long). Performance is good this way, much better than DLookup methods I had tried. If I had to do it over again, I may have setup SQL Express and used unpivot or cross join for this workflow as that probably would have been less time consuming than researching alternative ways and eventually writing and testing a VBA routine.
Dim aux_table, main_table, query_sort_name, main_table_catsource, str_query_category_subloop, str_query_category_union As String
'Define Name
aux_table = "AuxTable_Series"
main_table = "VC3_Series_vs_Input_Duty_Env_Filter_DBR_Cert"
main_table_catsource = "VSD_Series"
query_sort_name = "autoqry_Series_"
'Load Aux_table to recordset
Set rs_AuxTable = CurrentDb.OpenRecordset(aux_table)
'Loop through each Aux Table Column/Field
For Each aux_field In rs_AuxTable.Fields
'Set Aux Column Name
'MsgBox aux_field.Name
'Get Count of Records for Column
Set rs_count = CurrentDb.OpenRecordset("SELECT COUNT(" & aux_field.Name & ") AS RecCount FROM " & aux_table)
'MsgBox rs_count.reccount
rs_AuxTable.MoveFirst
i = 0
str_query_category_union = ""
Do While i < rs_count.reccount
'MsgBox rs_AuxTable.Fields(aux_field.Name)
'Same Category Union Query
str_query_category_subloop = "SELECT " & main_table & "." & main_table_catsource & "," & main_table & "." _
& rs_AuxTable.Fields(aux_field.Name) & " AS " & aux_field.Name & " FROM " & main_table & " WHERE " _
& main_table & "." & rs_AuxTable.Fields(aux_field.Name) & " Is Not Null"
'MsgBox rs_AuxTable.Fields(aux_field.Name)
If i = 0 Then
str_query_category_union = str_query_category_subloop
Else
str_query_category_union = str_query_category_union & " UNION " & str_query_category_subloop
End If
rs_AuxTable.MoveNext
i = i + 1
Loop
rs_AuxTable.MoveFirst
i = 0
'MsgBox str_query_category_union
CurrentDb.CreateQueryDef query_sort_name & aux_field.Name, str_query_category_union
Next
rs_AuxTable.Close
rs_count.Close
Set rs_AuxTable = Nothing
Set rs_count = Nothing
Set aux_field = Nothing
End Sub

Related

Oracle: get countries separated by N borders

I would like to get all countries separated by N (1,2,3,4 ...) borders from a specified country.
N should also be specified.
For example I have the table "borders" and "country":
border | neighbor
-----------------
FR | DE
FR | IT
IT | FR
DE | FR
DE | PL
PL | DE
DE | DK
DK | DE
CODE COUNTRYNAME
---- ---------
FR France
DE Germany
RU Russia
IT Italy
PL Poland
DK Denmark
N = 2 & country = France
If I want to get countries separated by 2 borders from France, it should return Poland (FR -> DE -> PL) and Denmark (FR -> DE -> DK)
N = 1 & country = France
If I want to get countries separated by 1 border from France, it should return Germany (FR -> DE) and Italy (FR -> IT)
I can modify borders if needed.
I tried some hierarchical queries without success.
Thanks
BR
Here's a complete enumeration of all possible paths and their lengths, given a starting country and no limitation as to paths being the shortest possible paths between two countries (disclaimer, don't run this on too many countries):
WITH
countries AS (SELECT DISTINCT border country FROM t),
chains (country, path, destination, steps) AS (
SELECT country, country, country, 0
FROM countries
UNION ALL
SELECT chains.country, chains.path || '->' || t.neighbor, t.neighbor, chains.steps + 1
FROM chains
JOIN t ON chains.destination = t.border
AND chains.path NOT LIKE '%' || t.neighbor || '%' -- This prevents cycles
)
SELECT *
FROM chains
ORDER BY country, steps;
The result being:
| COUNTRY | PATH | DESTINATION | STEPS |
|---------|----------------|-------------|-------|
| DE | DE | DE | 0 |
| DE | DE->PL | PL | 1 |
| DE | DE->FR | FR | 1 |
| DE | DE->DK | DK | 1 |
| DE | DE->FR->IT | IT | 2 |
| DK | DK | DK | 0 |
| DK | DK->DE | DE | 1 |
| DK | DK->DE->FR | FR | 2 |
| DK | DK->DE->PL | PL | 2 |
| DK | DK->DE->FR->IT | IT | 3 |
| FR | FR | FR | 0 |
| FR | FR->IT | IT | 1 |
| FR | FR->DE | DE | 1 |
| FR | FR->DE->DK | DK | 2 |
| FR | FR->DE->PL | PL | 2 |
| IT | IT | IT | 0 |
| IT | IT->FR | FR | 1 |
| IT | IT->FR->DE | DE | 2 |
| IT | IT->FR->DE->PL | PL | 3 |
| IT | IT->FR->DE->DK | DK | 3 |
| PL | PL | PL | 0 |
| PL | PL->DE | DE | 1 |
| PL | PL->DE->FR | FR | 2 |
| PL | PL->DE->DK | DK | 2 |
| PL | PL->DE->FR->IT | IT | 3 |
SQLFiddle here.
Store the query in a view and then you can filter on it, e.g.
SELECT * FROM my_view WHERE country = 'FR' AND steps = 2
Side-note on shortest paths:
If you actually did need the shortest paths between two countries, just reuse
that view again picking an arbitrary path when two paths tie (again, this isn't the most efficient solution, don't do this for too many countries!):
SELECT
country,
destination,
MIN(steps) KEEP (DENSE_RANK FIRST ORDER BY steps) AS steps,
MIN(path) KEEP (DENSE_RANK FIRST ORDER BY steps) AS path
FROM paths
WHERE country != destination
GROUP BY country, destination
ORDER BY country, destination
And get:
| COUNTRY | DESTINATION | STEPS | PATH |
|---------|-------------|-------|----------------|
| DE | DK | 1 | DE->DK |
| DE | FR | 1 | DE->FR |
| DE | IT | 2 | DE->FR->IT |
| DE | PL | 1 | DE->PL |
| DK | DE | 1 | DK->DE |
| DK | FR | 2 | DK->DE->FR |
| DK | IT | 3 | DK->DE->FR->IT |
| DK | PL | 2 | DK->DE->PL |
| FR | DE | 1 | FR->DE |
| FR | DK | 2 | FR->DE->DK |
| FR | IT | 1 | FR->IT |
| FR | PL | 2 | FR->DE->PL |
| IT | DE | 2 | IT->FR->DE |
| IT | DK | 3 | IT->FR->DE->DK |
| IT | FR | 1 | IT->FR |
| IT | PL | 3 | IT->FR->DE->PL |
| PL | DE | 1 | PL->DE |
| PL | DK | 2 | PL->DE->DK |
| PL | FR | 2 | PL->DE->FR |
| PL | IT | 3 | PL->DE->FR->IT |
As can be seen in this SQL Fiddle, or again, with a bit more data.
You can aggregate the neighbours of each country into a collection and then use a simple hierarchical query to find the (non-cyclic) paths:
SQL Fiddle
Oracle 11g R2 Schema Setup:
create table borders (border char(2), neighbor char(2));
insert into borders values ('FR','DE');
insert into borders values ('FR','IT');
insert into borders values ('IT','FR');
insert into borders values ('DE','FR');
insert into borders values ('DE','PL');
insert into borders values ('PL','DE');
insert into borders values ('DE','DK');
insert into borders values ('DK','DE');
insert into borders values ('RU','PL');
insert into borders values ('PL','RU');
insert into borders values ('IT','CH');
insert into borders values ('FR','CH');
insert into borders values ('DE','CH');
insert into borders values ('CH','IT');
insert into borders values ('CH','FR');
insert into borders values ('CH','DE');
CREATE TYPE countrylist AS TABLE OF CHAR(2);
Query 1:
WITH neighbors ( country, neighbors ) AS (
SELECT border,
CAST( COLLECT( neighbor ) AS COUNTRYLIST )
FROM borders
GROUP BY border
)
SELECT SYS_CONNECT_BY_PATH( country, '->' ) AS path,
CONNECT_BY_ROOT( country ) AS origin,
country AS destination,
LEVEL - 1 AS path_length
FROM neighbors
WHERE LEVEL - 1 = 4 -- Remove this to find paths of any length
START WITH country = 'FR' -- Remove this to start from any country
CONNECT BY NOCYCLE
country MEMBER OF PRIOR neighbors
Results:
| PATH | ORIGIN | DESTINATION | PATH_LENGTH |
|----------------------|--------|-------------|-------------|
| ->FR->CH->DE->PL->RU | FR | RU | 4 |
| ->FR->IT->CH->DE->DK | FR | DK | 4 |
| ->FR->IT->CH->DE->PL | FR | PL | 4 |
Explain Plan:
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16 | 608 | 5 | 00:00:01 |
| * 1 | FILTER | | | | | |
| * 2 | CONNECT BY NO FILTERING WITH START-WITH | | | | | |
| 3 | VIEW | | 16 | 608 | 4 | 00:00:01 |
| 4 | SORT GROUP BY | | 16 | 128 | 4 | 00:00:01 |
| 5 | TABLE ACCESS FULL | BORDERS | 16 | 128 | 3 | 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter(LEVEL-1=4)
* 2 - filter("COUNTRY"MEMBER OFPRIOR "NEIGHBORS" AND "COUNTRY"='FR')
Query 2 This will get the shortest path (with ties) between pairs of countries:
WITH neighbors ( country, neighbors ) AS (
SELECT border,
CAST( COLLECT( neighbor ) AS COUNTRYLIST )
FROM borders
GROUP BY border
)
SELECT path,
origin,
destination,
path_length
FROM (
SELECT SYS_CONNECT_BY_PATH( country, '->' ) AS path,
CONNECT_BY_ROOT( country ) AS origin,
country AS destination,
LEVEL - 1 AS path_length,
RANK() OVER (
PARTITION BY CONNECT_BY_ROOT( country ), country
ORDER BY LEVEL ASC
) AS path_length_rank
FROM neighbors
WHERE LEVEL > 1
CONNECT BY NOCYCLE
country MEMBER OF PRIOR neighbors
ORDER BY origin, destination
)
WHERE path_length_rank = 1
Results:
| PATH | ORIGIN | DESTINATION | PATH_LENGTH |
|----------------------|--------|-------------|-------------|
| ->CH->DE | CH | DE | 1 |
| ->CH->DE->DK | CH | DK | 2 |
| ->CH->FR | CH | FR | 1 |
| ->CH->IT | CH | IT | 1 |
| ->CH->DE->PL | CH | PL | 2 |
| ->CH->DE->PL->RU | CH | RU | 3 |
| ->DE->CH | DE | CH | 1 |
| ->DE->DK | DE | DK | 1 |
| ->DE->FR | DE | FR | 1 |
| ->DE->FR->IT | DE | IT | 2 |
| ->DE->CH->IT | DE | IT | 2 |
| ->DE->PL | DE | PL | 1 |
| ->DE->PL->RU | DE | RU | 2 |
| ->DK->DE->CH | DK | CH | 2 |
| ->DK->DE | DK | DE | 1 |
| ->DK->DE->FR | DK | FR | 2 |
| ->DK->DE->FR->IT | DK | IT | 3 |
| ->DK->DE->CH->IT | DK | IT | 3 |
| ->DK->DE->PL | DK | PL | 2 |
| ->DK->DE->PL->RU | DK | RU | 3 |
| ->FR->CH | FR | CH | 1 |
| ->FR->DE | FR | DE | 1 |
| ->FR->DE->DK | FR | DK | 2 |
| ->FR->IT | FR | IT | 1 |
| ->FR->DE->PL | FR | PL | 2 |
| ->FR->DE->PL->RU | FR | RU | 3 |
| ->IT->CH | IT | CH | 1 |
| ->IT->FR->DE | IT | DE | 2 |
| ->IT->CH->DE | IT | DE | 2 |
| ->IT->CH->DE->DK | IT | DK | 3 |
| ->IT->FR->DE->DK | IT | DK | 3 |
| ->IT->FR | IT | FR | 1 |
| ->IT->CH->DE->PL | IT | PL | 3 |
| ->IT->FR->DE->PL | IT | PL | 3 |
| ->IT->FR->DE->PL->RU | IT | RU | 4 |
| ->IT->CH->DE->PL->RU | IT | RU | 4 |
| ->PL->DE->CH | PL | CH | 2 |
| ->PL->DE | PL | DE | 1 |
| ->PL->DE->DK | PL | DK | 2 |
| ->PL->DE->FR | PL | FR | 2 |
| ->PL->DE->CH->IT | PL | IT | 3 |
| ->PL->DE->FR->IT | PL | IT | 3 |
| ->PL->RU | PL | RU | 1 |
| ->RU->PL->DE->CH | RU | CH | 3 |
| ->RU->PL->DE | RU | DE | 2 |
| ->RU->PL->DE->DK | RU | DK | 3 |
| ->RU->PL->DE->FR | RU | FR | 3 |
| ->RU->PL->DE->FR->IT | RU | IT | 4 |
| ->RU->PL->DE->CH->IT | RU | IT | 4 |
| ->RU->PL | RU | PL | 1 |
Explain Plan:
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16 | 32576 | 6 | 00:00:01 |
| * 1 | VIEW | | 16 | 32576 | 6 | 00:00:01 |
| 2 | SORT ORDER BY | | 16 | 608 | 6 | 00:00:01 |
| * 3 | WINDOW SORT PUSHED RANK | | 16 | 608 | 6 | 00:00:01 |
| * 4 | FILTER | | | | | |
| * 5 | CONNECT BY WITHOUT FILTERING | | | | | |
| 6 | VIEW | | 16 | 608 | 4 | 00:00:01 |
| 7 | SORT GROUP BY | | 16 | 128 | 4 | 00:00:01 |
| 8 | TABLE ACCESS FULL | BORDERS | 16 | 128 | 3 | 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("PATH_LENGTH_RANK"=1)
* 3 - filter(RANK() OVER ( PARTITION BY ANY,"COUNTRY" ORDER BY LEVEL)<=1)
* 4 - filter(LEVEL>1)
* 5 - filter("COUNTRY"MEMBER OFPRIOR "NEIGHBORS")
Your BORDERS table contains reciprocal relationships (e.g. FR->DE, DE->FR) . This means you need to handle cycles. This is not straightforward at all, because you want to avoid say FR->DE->PL->DE at three degrees of separation.
I have here a recursive WITH clause, (so Oracle 11gR2 or later) which does this.
with hqry (path, nghbr, prev_bdr, root_bdr, lvl) as (
select b.border
, b.neighbor
, b.border
, b.border
, 1 as lvl
from borders b
where b.border = 'FR'
union all
select hqry.path || '->' || b.border
, b.neighbor
, hqry.nghbr
, hqry.root_bdr
, hqry.lvl + 1
from hqry
join borders b on b.border = hqry.nghbr
where b.neighbor != hqry.root_bdr
and b.neighbor != hqry.prev_bdr
and hqry.lvl < 3 -- this is a nasty kludge, with more time I'd like to fix it
)
SEARCH DEPTH FIRST BY path SET order1
CYCLE path SET cycle TO 1 DEFAULT 0
select path || '->' || nghbr as end_path
from hqry
where hqry.lvl = 3
;
It takes five parameters
path - the previous chain of borders
nghbr - the current neighbor, stating with the root country i.e. France
prev_bdr - the immediate previous border to prevent FR->DE->PL->DE
root_bdr - the originating border to prevent FR->CH->IT->FR
lvl - to track the degrees of separation
Sample output for three degrees of separation:
FR->CH->DE->DK
FR->CH->DE->PL
FR->DE->CH->IT
FR->DE->PL->RU
FR->IT->CH->DE
There is a SQL Fiddle demo here. I added in a couple more countries: Switzerland adds some nasty edges cases.
Obviously the above output shows it doesn't enforce the shortest path algorithm, that is left as an exercise for the reader :) If you're interested in adding this - and you should be, because I think it's key to a robust solution - I suggest you real this post by Lucas Jellema.
You could use CONNECT_BY_ROOT to find the neighbors and filter by LEVEL to find the nth neighbor.
SELECT *
FROM (
SELECT border
,connect_by_root(neighbor) AS neighbor
FROM borders
WHERE border = :ctry
AND LEVEL = :n
CONNECT BY NOCYCLE
PRIOR border = neighbor
) WHERE neighbor != :ctry
Demo

Excel vba - How to replace a cell with a complex value

I have two sheets. WIRES and BOM.
WIRES looks like this:
| Ltg-Nr_ | Kurzname | Pin | Kurzname | Pin | Farbe |
|---------|----------|-----|----------|-----|-------|
| 712001 | AJ4 | 11 | LSTS | 7 | GE |
| 712002 | AJ4 | 10 | LSTS | 8 | SW |
| 712003 | KM_23.1 | 1 | KM_12.4 | 1 | BR |
| 712004 | AJ4 | 19 | GSR2 | 2 | GN |
| 712005 | AJ4 | 18 | GSR2 | 1 | SW |
| 712006 | AJ4 | 46 | CR_31AB | 1 | BR |
| 712007 | AJ4 | 49 | CR_CANP | 1 | OR/SW |
| 712008 | AJ4 | 50 | CR_CANM | 1 | OR/BR |
BOM looks like this:
| Con |
|------|
| GSR2 |
| AJ4 |
I want to do a macro in excel to search for each values from rows in sheet BOM, in sheet WIRES, and where it find the value to replace with value_"cell_in_front_of_it". After this put 1 in front of cells replaced.
For example, it has to search for GSR2 in sheet WIRES and where it find GSR2 to replase it with GSR2_2; next row replace GSR2 with GSR2_1.
After macro run i want table to look like this:
| Ltg-Nr_ | Kurzname | Pin | Kurzname | Pin | Farbe |
|---------|----------|-----|----------|-----|-------|
| 712001 | AJ4 | 11 | LSTS | 7 | GE |
| 712002 | AJ4 | 10 | LSTS | 8 | SW |
| 712003 | KM_23.1 | 1 | KM_12.4 | 1 | BR |
| 712004 | AJ4 | 19 | "GSR2_2" | "1" | GN |
| 712005 | AJ4 | 18 | "GSR2_1" | "1" | SW |
| 712006 | AJ4 | 46 | CR_31AB | 1 | BR |
| 712007 | AJ4 | 49 | CR_CANP | 1 | OR/SW |
| 712008 | AJ4 | 50 | CR_CANM | 1 | OR/BR |
I tried this:
I tried something like this:
Sub Macro1()
'
' Macro1 Macro
'
'
Dim Col As Integer
Dim Row As Integer
For Col = 2 To 4
For Row = 2 To 10
colo = Row + 1
Rows = Row + 1
Sheets("WIRES").Columns(2).Replace What:=Sheets("BOM").Cells(Row, 1).Text, Replacement:=Sheets("WIRES").Cells(Row, 2).Text & "_" & Sheets("WIRES").Cells(Rows, colo).Text, LookAt:=xlWhole, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Next Row
Next Col
End Sub
I made this, and it worked exactly as i wanted.
Thanks for your answers.
Dim roww, rowb As Integer
For roww = 2 To 150
For rowb = 1 To 10
Sheets("WIRES").Select
Cells(roww, 2).Select
If Selection.Value = Sheets("BOM").Cells(rowb, 1).Value Then
Selection.Value = Selection.Value & "_" & Selection.Offset(0, 1)
Selection.Offset(0, 1).Value = "1"
End If
Sheets("WIRES").Select
Cells(roww, 4).Select
If Selection.Value = Sheets("BOM").Cells(rowb, 1).Value Then
Selection.Value = Selection.Value & "_" & Selection.Offset(0, 1)
Selection.Offset(0, 1).Value = "1"
End If
Next rowb
Next roww

Remove a specific word and everything after in a Cell

I'm having trouble deleting everything after and including the word APT and STE on Address column
If you look at the result blow, my vba code is deleting the word that the letters ste ( 2121 STEVENSON LN) or apt.
What is best way to to remove the word APT or STE and everything after that?
Below is my code,
Option Explicit
Sub Remove()
Dim Sht As Worksheet
Set Sht = ActiveWorkbook.Sheets("Data")
With Sht.Range("E:E")
.Replace "APT*", "", xlPart
.Replace "STE*", "", xlPart
End With
End Sub
My Data
+-------+-----+-----+----------+----------------------------------+-------+------+-----+
| Route | Pcs | Wgt | Location | Address | Suite | City | Zip |
+-------+-----+-----+----------+----------------------------------+-------+------+-----+
| SD-26 | 1 | 3 | | 5555 SOUTHWESTERN BLVD | | | |
| SD-26 | 1 | 7 | | 6666 EASTERN AVE APT 100 | | | |
| SD-05 | 1 | 1 | | 161112 HOMESTEAD ST | | | |
| SD-05 | 2 | 8 | | 2221 STEVENSON LN | | | |
| SD-04 | 1 | 8 | | 4040 OLD DENTON RD APT 2104 | | | |
| SD-04 | 1 | 3 | | 15811 E FRANKFORD RD APT 1507 | | | |
| SD-04 | 1 | 1 | | 835 WESTMINSTER DR | | | |
| SD-03 | 1 | 5 | | 9001 LAKESIDE CIR APT 5203 | | | |
| SD-03 | 1 | 3 | | 8880 UNION STATION PKWY APT 2104 | | | |
| SD-03 | 1 | 1 | | 420 E MAIN ST STE E | | | |
+-------+-----+-----+----------+----------------------------------+-------+------+-----+
Result
+-------+-----+-----+----------+--------------------------+-------+------+-----+
| Route | Pcs | Wgt | Location | Address | Suite | City | Zip |
+-------+-----+-----+----------+--------------------------+-------+------+-----+
| SD-26 | 1 | 3 | | 5555 SOUTHWE | | | |
| SD-26 | 1 | 7 | | 6666 EA | | | |
| SD-05 | 1 | 1 | | 161112 HOME | | | |
| SD-05 | 2 | 8 | | 2221 | | | |
| SD-04 | 1 | 8 | | 4040 OLD DENTON RD | | | |
| SD-04 | 1 | 3 | | 15811 E FRANKFORD RD | | | |
| SD-04 | 1 | 1 | | 835 WESTMIN | | | |
| SD-03 | 1 | 5 | | 9001 LAKESIDE CIR | | | |
| SD-03 | 1 | 3 | | 8880 UNION STATION PKWY | | | |
| SD-03 | 1 | 1 | | 420 E MAIN ST | | | |
+-------+-----+-----+----------+--------------------------+-------+------+-----+
Seems to me you can just include a space before and after APT/STE but before the wildcard character.
Sub RemoveAptSte()
Dim Sht As Worksheet
Set Sht = ActiveWorkbook.Sheets("Data")
With Sht.Range("E:E")
.Replace " APT *", vbNullString, xlPart
.Replace " STE *", vbNullString, xlPart
End With
End Sub
That should remove just about any false positive from consideration.
  

Access Query for Ranking/Assigning Priority Values

I am doing data conversion from a previous system that was keyed in without validation rules. I am working with a table of Emergency Contacts, and trying to assign a primary contact with (Y/N) when the field is blank or duplicated (i.e. someone puts Y or N for multiple contacts I want to arbitrarily assign primary). I will also assign a new column with an alphabetic sequence (a, b, c, etc.) based on the priority which was designated in the other column.
Every ID must only have 1 Priority 'Y'.
Current Table:
+--------+---------+----------+
| id | fname | pri_cont |
+--------+---------+----------+
| 001000 | Rox | Y |
| 001000 | Dan | N |
| 001002 | May | Y |
| 001007 | Lee | Y |
| 001007 | Clive | Y |
| 001008 | Max | Y |
| 001008 | Kim | N |
| 001013 | Sam | Y |
| 001013 | Ann | |
| 001014 | Nat | Y |
| 001018 | Bruce | Y |
| 001018 | Mel | |
| 001020 | Wilson | Y |
| 001022 | Goi | Y |
| 001022 | Adele | N |
| 001022 | Gary | N |
+--------+---------+----------+
What I want:
+--------+---------+----------+----------+
| id | fname | pri_cont | priority |
+--------+---------+----------+----------+
| 001000 | Rox | Y | a |
| 001000 | Dan | N | b |
| 001002 | May | Y | a |
| 001007 | Lee | Y | a |
| 001007 | Clive | N | b |
| 001008 | Max | Y | a |
| 001008 | Kim | N | b |
| 001013 | Sam | Y | a |
| 001013 | Ann | N | b |
| 001014 | Nat | Y | a |
| 001018 | Bruce | Y | a |
| 001018 | Mel | N | b |
| 001020 | Wilson | Y | a |
| 001022 | Goi | Y | a |
| 001022 | Adele | N | b |
| 001022 | Gary | N | c |
+--------+---------+----------+----------+
How can I do that?
Well, as I see it your cleanup requires several queries (please note queries assume Emergency Contacts table has a unique autonumber, dbID):
One Select Query to count Y and N instances. Also, query can calculate Priority column using the Chr ASCII conversion of numbers to letters.:
SELECT t1.ID, t1.fname, t1.pri_cont,
(SELECT Count(*)
FROM EmergContacts t2
WHERE t1.dbID >= t2.dbID AND t1.ID = t2.ID
AND t1.pri_cont = t2.pri_cont AND t1.pri_cont = 'Y') AS YCount,
(SELECT Count(*)
FROM EmergContacts t3
WHERE t1.dbID >= t3.dbID AND t1.ID = t3.ID
AND t1.pri_cont = t3.pri_cont AND t1.pri_cont = 'N') AS NCount,
(SELECT Chr(Count(t2.ID) + 96)
FROM EmergContacts t2
WHERE t1.dbID >= t2.dbID AND t1.ID = t2.ID) AS Priority
FROM EmergContacts AS t1;
With output such as below:
ID | fname | pri_cont | YCount | NCount | Priority
1000 | Rox | Y | 1 | 0 | a
1000 | Dan | N | 0 | 1 | b
1002 | May | Y | 1 | 0 | a
1007 | Lee | Y | 1 | 0 | a
1007 | Clive | Y | 2 | 1 | b
1008 | Max | Y | 1 | 0 | a
1008 | Kim | N | 0 | 1 | b
1013 | Sam | Y | 1 | 0 | a
1013 | Ann | | 0 | 1 | b
1014 | Nat | Y | 1 | 0 | a
1018 | Bruce | Y | 1 | 0 | a
1018 | Mel | | 0 | 1 | b
1020 | Wilson | Y | 1 | 0 | a
1022 | Goi | Y | 1 | 0 | a
1022 | Adele | N | 0 | 1 | b
1022 | Gary | N | 0 | 2 | c
From there you run three update queries:
To clean up Nulls:
UPDATE EmergContacts
SET pri_cont = 'N'
WHERE pri_cont Is Null;
To clean up IDs with more than 1 Ys:
UPDATE EmergContacts
SET pri_cont = 'N'
WHERE ID IN (SELECT ID FROM EmergContPrCount WHERE YCount > 1)
AND fName IN (SELECT fName FROM EmergContPrCount WHERE YCount > 1);
And to clean up IDs with no Ys:
UPDATE EmergContacts
SET pri_cont = 'Y'
WHERE (ID IN (SELECT ID FROM EmergContPrCount WHERE YCount = 0)
AND fName IN (SELECT Max(fName) FROM EmergContPrCount WHERE YCount = 0));

Turning a multiple If statement formula into VBA

I currently have the following formula inside a column of cells but as you can see its large and messy and I am afraid that the cells might get edited by someone working in the workbook accidentally.
So I have tried to code it in VBA but I keep getting a Run-Time Error '91'. And I am stuck as to what I need to adjust to make it operate.
thanks for your help
Current Formula
=IF(B7=$H$5,"1",IF(B7=$H$6,".75",IF(B7=$H$7,".75",IF(B7=$H$8,"1",IF(B7=$H$9,"1",IF(B7=$H$10,"1",IF(B7=$H$11,".5",IF(B7=$H$12,".5",IF(B7=$H$13,".5",IF(B7=$H$14,".5",IF(B7=$H$15,"1",IF(B7=$H$16,".75",IF(B7=$H$17,"1",IF(B7=$H$18,"1",IF(B7=$H$19,".75",IF(B7=$H$20,"1",IF(B7=$H$21,"1",IF(B7=$H$22,"1",IF(B7=$H$23,"1",IF(B7=$H$24,".75",IF(B7=$H$25,"1",IF(B7=$H$26,".75",IF(B7=$H$27,".5",IF(B7=$H$28,"1",IF(B7=$H$29,".75",IF(B7=$H$30,".5",IF(B7=$H$31,"1",IF(B7=$H$32,"1",IF(B7=$H$33,"1",IF(B7=$H$34,".5",IF(B7=$H$35,"1",IF(B7=$H$36,".25",IF(B7=$H$37,"1",IF(B7=$H$38,"1",IF(B7=$H$39,"1",IF(B7=$H$40,"1",IF(B7=$H$41,"1",IF(B7=$H$42,"1",IF(B7=$H$43,"1",IF(B7=$H$44,"1",IF(B7=$H$45,"1",IF(B7=$H$46,"1",IF(B7=$H$47,"1",IF(B7=$H$48,"1",IF(B7=$H$49,"1",IF(B7=$H$50,".5",IF(B7=$H$51,"1",IF(B7=$H$52,".25",IF(B7=$H$53,"1",IF(B7=$H$54,".75",IF(B7=$H$55,"1",IF(B7=$H$56,"1",IF(B7=$H$57,"1")))))))))))))))))))))))))))))))))))))))))))))))))))))
My attempt at turning it into VBA code
Sub Macro()
Dim Whole as long
Dim Third as long
Dim half as long
Dim quarter as long
Dim lookat as range
Dim answer as range
Whole = 1
third = .75
Half = .5
Quarter = .25
Lookat = Worksheets("sheet1".Range("B2:B300")
Answer = worksheets("Sheet1").range("C2:C300")
If Lookat = "AAAA" Or "AAAB" Or "AAAC" Or "AAAD" Or "AAAE" Or "AAAF" Or "AAAG" Or "AAAH" Or "AAAI" Or "AAAJ" Or "AAAK" Or "AAAL" Or "AAAM" Or "AAAN" Or "AAAO" Or "AAAP" Or "AAAQ" Or "AAAR" Or "AAAS" Or "AAAT" Or "AAAU" Or "AAAV" _
Or "AAAW" Or "AAAX" Or "AAAY" Or "AAAZ" Or "BBBA" Or "BBBB" Or "BBBC" Or "BBBD" Or "BBBE" Or "BBBF" Or "BBBG" Then
Answer.value=whole
ElseIf Lookat = "AAA" Or "AAB" Or "AAC" Or "AAD" Or "AAE" Or "AAF" Or "AAG" Or "AAH" Then
Answer.Value = Third
ElseIf Lookat = "AA" Or "AB" Or "AC" Or "AD" Or "AE" Or "AF" Or "AG" Or "AH" Then
Answer.Value = Half
ElseIf Lookat = "A" Or "B" Then
Answer.Value = Quarter
end if
End Sub
1 Protect your Workbook Link or hide it in a worksheet
2 Create your DataBase (your 'H' column)
3 In 'I' Column put your Weight [whole, third, half, quarter]. Sample:
+---------+--------+
| COL 'H' | HEIGHT |
+---------+--------+
| 6 | 1 |
| 9 | 0,5 |
| 4 | 0,75 |
| 6 | 1 |
| 8 | 0,5 |
| 1 | 0,75 |
| 5 | 1 |
| 4 | 0,5 |
| 5 | 0,75 |
| 7 | 1 |
| 4 | 0,5 |
| 9 | 0,75 |
| 1 | 1 |
| 8 | 0,5 |
| 1 | 0,75 |
| 5 | 1 |
| 1 | 0,5 |
| 4 | 0,75 |
| 4 | 1 |
| 1 | 0,5 |
| 7 | 0,75 |
+---------+--------+
4 Change your current formula to:
=VLOOKUP(B8,H:I,2,FALSE)
PS: You can try to name your Database to make your code better to understand Link.
Something like this may suit:
+----+-----+------+
| | A | B |
+----+-----+------+
| 1 | H10 | 1 |
| 2 | H14 | 0.5 |
| 3 | H15 | 1 |
| 4 | H16 | 0.75 |
| 5 | H18 | 1 |
| 6 | H19 | 0.75 |
| 7 | H23 | 1 |
| 8 | H24 | 0.75 |
| 9 | H25 | 1 |
| 10 | H26 | 0.75 |
| 11 | H27 | 0.5 |
| 12 | H28 | 1 |
| 13 | H29 | 0.75 |
| 14 | H30 | 0.5 |
| 15 | H33 | 1 |
| 16 | H34 | 0.5 |
| 17 | H35 | 1 |
| 18 | H36 | 0.25 |
| 19 | H49 | 1 |
| 20 | H5 | 1 |
| 21 | H50 | 0.5 |
| 22 | H51 | 1 |
| 23 | H52 | 0.25 |
| 24 | H53 | 1 |
| 25 | H54 | 0.75 |
| 26 | H57 | 1 |
| 27 | H7 | 0.75 |
+----+-----+------+
located in a sheet on its own in the same workbook and the array named say Vt of Workbook Scope.
This might then be used as the lookup table with a formula such as:
=VLOOKUP(A1,Vt,2)
where A1 contains a value such as "H10" for the purposes of this example.
It is important to sort A:B of the 'other' (to-be-hidden/protected) sheet in ascending order of ColumnA if to take advantage of a table that does not specifically equate every possible value. The lack of a fourth parameter in the VLOOKUP formula (though often causing problems!) means that an approximate match will be found where there is no exact match.