So basically, I have two table, X and Y. I want to join them with the substring-ed value but I'm unsure of how I can do so.
Sample code of X:
select distinct
trim(ws.WS_name) as [WS Name],
substring(trim(e.equip_id),1,8) as [Equid ID],
into #eqm_hist
from eqmhist
Sample table of X:
WS name
Equid ID
WS 21
KTRGAF7L
WS 21
KTRGAF7L
Sample code of Y:
select distinct
[Batch ID],
[Qty],
rtrim(flh.tracking_interface_id) as [Tool],
[WS Name],
into #main
from flh
Sample table of Y:
Batch ID
Qty
Tool
12345
100
KTRGAF7L00
23456
100
KTRGAF7L00
Do note that [Tool] and [Equid ID] is the same
How can I join them together using the substring-ed values to achieve the table like below?
Do I also have to remove the last two digit for [Tool] in table Y to do so?
Batch ID
Qty
Tool
WS Name
12345
100
KTRGAF7L00
WS 21
23456
100
KTRGAF7L00
WS 21
Per the first answer to this question, it appears that SQL Server will optimize a LIKE 'prefix%' condition to use an index.
So if you have an index on Y(Tool), you should be able to efficiently run the query:
SELECT *
FROM X
JOIN Y ON Y.Tool LIKE X.[Equid ID] + '%'
Follow-up note: If [Equid ID] values may have variable length, but the tool values will always have exactly two extra characters, you should change join condition to ON Y.Tool LIKE X.[Equid ID] + '__'. Underscores are single-character wildcards. This will handle vases where you have [Equid ID] values "Thing" and "ThingA" with Tool values "Thing01", "Thing02", "ThingA01", and "ThingA02".
Related
I have the xlsx sheet which has data for every month in the columns. I want to convert it to rows while I load it to QlikView
First Name
Last Name
Home Owner
Mortgage
44562
44593
44621
44652
A
FSFD
Y
Y
34343
48768
87788
878878
DGD
KJJHK
Y
N
5454
454
4545
74878
FDQE
TERTER
N
N
78676
787897
454654
7787
RTE
YRTYZ
Y
N
78634
545
4787
5744
SAS
TRGFV
N
N
6764
54465
1215
4878
In this case you can use CrossTable load.
From the documentation:
The crosstable prefix is used to turn a cross table into a straight table, that is, a wide table with many columns is turned into a tall table, with the column headings being placed into a single attribute column.
In your case we can have script like this:
Data:
CrossTable([Month], [Value], 4)
LOAD
[First Name],
[Last Name],
[Home Owner],
Mortgage,
[44562],
[44593],
[44621],
[44652]
FROM
[C:\Users\USER\Documents\data.xlsx]
(ooxml, embedded labels, table is Sheet1)
;
Once the script the is reloaded the resulted table will be:
CrossTable(Month, Value, 4) is the important bit. The values in the the brackets are stating that: After the 4th column, move the top row (header) as column and name the new column Month, name the values against it Value (you can see the new Month and Value columns in the screenshot). Month and Value are made-up names and the can be named whatever you want.
I have a MS Access table in Access 2003 database named Comments and a column named Sequence Number in the Comments table. The Sequence Number column has numbers ranging from 1 to 20000. However, there are certain numbers missing from the Sequence Number column and I want to be able to view the numbers that are missing, e.g below I want to run a access query to see that 4 is missing.
Sequence Number
1
2
3
5
6
I'm using the following Access query in SQL view to get what I want.
SELECT ([Sequence Number]+1) AS MissingFrom, DMin("Sequence Number","Comments","Sequence Number>" & [Sequence Number]) AS MissingUntil
FROM Comments
WHERE (((DMin("Sequence Number","Comments","Sequence Number>" & [Sequence Number]))<>([Sequence Number]+1)));
However, when I run the query, I get the following error:
Syntax error (missing operator) in query expression 'Min(Sequence Number)'.
Can someone please point out what is causing the query to fail? Thanks!
With NOT EXISTS:
SELECT MIN([Sequence Number]) + 1
FROM Comments AS c
WHERE
c.[Sequence Number] < (SELECT MAX([Sequence Number]) FROM Comments)
AND NOT EXISTS (
SELECT 1 FROM Comments
WHERE [Sequence Number] = c.[Sequence Number] + 1
)
You can get the first in a missing series using:
select num + 1
from comments
where num + 1 not in (select num from comments) and
num + 1 <> (select max(num) from comments);
I have a query on grouping which I need to do a quick fix on. I am at present grouping column A and counting the value in column B.
select
Column A,
Count ([Column B])
from table1
Group by Column A
The issue is that column A has some entries which are not standard for example.
ABC 100
ABC~ 3
BCA 120
BCA* 4
I need to blast the data to fix long term, but there are 3m rows, so not a quick job, as I need to create a mapping file to deal with the problem.
I currently get returned duplicate entries which is right in theory, but in practice I would like to group the ABC, by either trimming the column to only 3 characters or doing a right. However I have tried it in the select statement and it just removes the ~ or * entry and sums the standard ABC or BCA.
Have you tried something ???
select LEFT([Column A], 3),
Count ([Column B])
from table1
Group by LEFT([Column A], 3)
I have a very simple query that returns the Notes field. Since there can be multiple notes, I only want the top 2. No problem. However, I'm going to be using the sql within another query. I really don't want 2 lines in my results. I would like to combine the results into 1 field value so I only have 1 result line in the results. Is this possible?
For example, I currently get the following:
12345 1001 500.00 "Note 1"
12345 1001 500.00 "Note 2"
What I would like to see is this:
12345 1001 500.00 "Note 1 AND Note 2"
Following is the sql:
select top 2 rcai.field_value
from rnt_agrs ra
inner join rnt_agr_inv_notes rain on ra.rnt_agr_nbr=rain.rea_rnt_agr_nbr
inner join RNT_CUST_ADDNL_INFO rcai on rain.rea_rnt_agr_nbr=rcai.rea_rnt_agr_nbr and rain.bac_acc_id=rcai.bac_acct_id
where ra.rnt_agr_nbr=128260511
Thanks for your help. I appreciate this forum for help with these issues.....
Get the next row's value and filter all but the first row:
select ..., rcai.field_value || ' AND '
min(rcai.field_value) -- next row's value (same as LEAD in Standard SQL)
over (partition by ra.rnt_agr_nbr
order by rcai.field_value
rows between 1 following and 1 following) as next_field_value
from rnt_agrs ra
inner join rnt_agr_inv_notes rain on ra.rnt_agr_nbr=rain.rea_rnt_agr_nbr
inner join RNT_CUST_ADDNL_INFO rcai on rain.rea_rnt_agr_nbr=rcai.rea_rnt_agr_nbr and rain.bac_acc_id=rcai.bac_acct_id
where ra.rnt_agr_nbr=128260511
qualify
row_number() -- only the first row
over (partition by ra.rnt_agr_nbr
order by rcai.field_value) = 1
If there might be only a single row you need to add a COALESCE(min...,'') to get rid of the NULL.
Both OLAP functions specify the same PARTITION and ORDER, so this is a single working step.
select *,(SELECT top 2 rcai.field_value + ' AND ' AS [text()]
FROM RNT_CUST_ADDNL_INFO rcai
WHERE rcai.rea_rnt_agr_nbr = rain.rea_rnt_agr_nbr
AND rcai.bac_acct_id=rain.bac_acc_id
FOR XML PATH('')) AS Notes
from
rnt_agrs ra inner join rnt_agr_inv_notes rain
on ra.rnt_agr_nbr=rain.rea_rnt_agr_nbr
I had something like this, where there was a 1 to many, and I wanted a semicolon delimited set of values in a single column with the main record.
You could use PIVOT to transform the two note rows into two note columns based on row number, then concatenate them. Here's an example:
SELECT pvt.[1] + ' and ' + pvt.[2]
FROM
( --the selection of your table data, including a row-number column
SELECT Msg, ROW_NUMBER() OVER(ORDER BY Id)
--sample data shown here, but this would be your real table
FROM (VALUES(1, 'Note 1'), (2, 'Note 2'), (3, 'Note 3')) Note(Id, Msg)
) Data (Msg, Row)
PIVOT (MAX(Msg) FOR Row IN ([1], [2])) pvt
Note that MAX is used for the aggregate in the PIVOT since an aggregate is required, but since ROW_NUMBER is unique, you're only aggregating a single value.
This could also be easily extended to the first N rows - just include the row numbers you want in the pivot and combine them as desired in the select statement.
I've been stuck with this problems for a while, and couldn't get it right yet. Here it is:
I have some tables in my Acces database and some querys. I have a query to select some fields and order by, say, their frequency. This is done for two tables, giving me two ranks. Looks like this (and are sorted DESC, so the higher Frequency is on top):
Table 1 Table 2
Value1 Frequency1 Value2 Frequency2
Table2.Value2 is a subset of Table1.Value1, so I want to match Value2 and Value1 plus Add a Column showing Value2 position (rank) on Table2, so I can compare it's position on Table1 and Table2 ranks.So I'll have something like:
Table3
Value1 Frequency1 Frequency2 PositionTable2
I've searched how to return the line number of a field (couldn't get it to work), and I can put the two tables together and match by Value, but can't get the result I need.
My knowledge of SQL is limited, and I don't understand VB at all, so please be nice :)
Thanks in advance
Edit
Example:
Table 1 Table 2
Name Frequency Name Frequency
Mary 5 Paul 2
John 4 John 1
Paul 3
Output I want:
Table 3
Name Frequency Frequency2 RankIn2
Mary 5 //doesn't appear in table2, freq=null rankin2=null
John 4 1 2 //second line of table2
Paul 3 2 1 //first line in table2
You might do this in two steps:
Step 1 -- Create a query (say, named "Table 2 with Rank") that calculates the rank for Table 2. The SQL might look something like this:
SELECT
[Table 2].[Name],
[Table 2].[Frequency],
Count(*) AS [Rank]
FROM
[Table 2],
[Table 2] AS [Self]
WHERE
[Self].[Frequency]>=[Table 2].[Frequency]
GROUP BY
[Table 2].[Name],
[Table 2].[Frequency];
If there are "ties" in Table 2 (that is, different names with the same frequency), this query will assign the same rank to both. If you don't want this, change the WHERE clause to specify how you want to break ties. For example, in the event of a tie, the WHERE clause...
WHERE
[Self].[Frequency]>[Table 2].[Frequency]
OR
([Self].[Frequency]=[Table 2].[Frequency] AND [Self].[Name]<=[Table 2].[Name])
...will assign the lower numbered rank to the name that comes first the in the alphabet.
Step 2 -- Create another query that joins the first query to Table 1. The SQL might look something like this:
SELECT
[Table 1].[Name],
[Table 1].[Frequency],
[Table 2 with Rank].[Frequency] AS [Frequency2],
[Table 2 with Rank].Rank AS [RankIn2]
FROM
[Table 1] LEFT JOIN [Table 2 with Rank]
ON [Table 1].[Name] = [Table 2 with Rank].[Name]
ORDER BY
[Table 1].[Frequency] DESC;
I would use VBA because Access' limited SQL doesn't understand the rank concept very well. Here are the steps.
Create a 3rd field for Table2 and call it Rank.
Create the following subroutine by pressing Alt+F11, Insert->Module and pasting the following code in the editor window that opens.
Public Sub RankTable()
Dim rs As Recordset, iRank As Integer, strQuery As String
strQuery = "SELECT * FROM Table2 ORDER BY Freq DESC"
Set rs = CurrentDb.OpenRecordset(strQuery, dbOpenDynaset)
rs.MoveFirst
iRank = 1
Do
rs.Edit
rs.Fields(3) = iRank
rs.Update
rs.MoveNext
iRank = iRank + 1
Loop While Not rs.EOF
rs.Close
End Sub
Run the above subroutine. (Remember you have to run this every time there is an update to Table2.)
Create the query
SELECT Table1.Name, Table1.Frequency, Table2.Frequency AS Frequency2, Table2.Rank
FROM Table1
LEFT OUTER JOIN Name ON Table1.Name = Table2.Name
ORDER BY Table2.Frequency