left join table on string like '%table.name%' - sql

I am trying to left join products.table and manufacturer.table to implement the manufacturer into the products table
The only problem there is no id linking the tables, so I am trying something like this.
SELECT [kArtikel]
,[cArtNr]
,a.[cName]
,a.[cBeschreibung]
,H.cName
,[cKurzBeschreibung]
,[cHersteller]
,[cHAN]
FROM [db].[dbo].[tartikel] a
left join [db].[dbo].[tHersteller] h on a.cName Like '%H.Cname%'
where cHersteller is null
But with this query I am recieving only H.cName = Null
After 2 min execute with the same number of products, having cHersteller = Null
While searching I only find examples where join is on some id with where clause. But this is not the possible here.

You are querying whether a.cName contains the literal H.Cname, which is probably not what you were gunning for. If you want to have wildcards around H.Cname, you can use the + operator:
SELECT [kArtikel]
,[cArtNr]
,a.[cName]
,a.[cBeschreibung]
,H.cName
,[cKurzBeschreibung]
,[cHersteller]
,[cHAN]
FROM [db].[dbo].[tartikel] a
LEFT JOIN [db].[dbo].[tHersteller] h ON a.cName LIKE '%' + H.Cname + '%'
WHERE cHersteller IS NULL

Related

Count the number of rows returned in SQL ORACLE

I have a little problem, my query look like this
select count(A.toto)
from B
inner join C
on B.tata = C.tata
inner join A
on C.tutu = A.tutu
group by A.toto, A.zaza, A.zozo;
and my result look like this :
1
2
1
6
7
4
1
1
1
But I want only the number of rows, for this example, the value that I would like to have is 9.
But I don't know how I can have this value...
Thank you in advance !!
You can use count(distinct). Unfortunately, Oracle doesn't support count(distinct) with multiple arguments, so a typical method is just to concatenate the value together:
select count(distinct A.toto || ':' || A.zaza || ':' || A.zozo)
from B inner join
C
on B.tata = C.tata inner join
A
on C.tutu = A.tutu;
This assumes that. the column values don't have the separator character (or at least in such a way that the concatenation is the same for rows with different key values).
An alternative method is to use a subquery:
select count(*)
from (select 1
from B inner join
C
on B.tata = C.tata inner join
A
on C.tutu = A.tutu
group by A.toto, A.zaza, A.zozo
) abc

Query doesn't seem to yield the correct results

I have a table with three fields, looks like this...........
tblValues
NameFrom NameTo Difference
abbbb arrrr 16
acccc agggg 20
adddd annnn 17
My query looks like this...
Select 'From' = tblValues.NameFrom,
'To' = tblValues.NameTo,
TblValues.Difference,
'Other' = x1.Difference
from tblValues
LEFT JOIN tblValues X1
ON tblValues.NameFrom = X1.NameTo
AND tblValues.NameTo = X1.NameFrom
WHERE tblValues.NameFrom Like '%a%' OR tblValues.NameTo Like '%a%'
ORDER BY tblValues.NameFrom, tblValues.NameTo
I let user search a text value in this case 'a'. I have about 30000 values that are not edited/updated by anyone. They've been entered into this table and have been as they are.
The data looks like this....
From To Difference Other
abbbb arrrr 16 16
.... ....
'Same for all the values - or at least that's what it should be!
The problem i have is that when I run this query there are a few records where OTHER = NULL - even though Difference has a value. Any idea why?
You are picking the value of other with this line
LEFT JOIN tblValues X1 ON tblValues.NameFrom = X1.NameTo
And you display it with this:
'Other' = x1.Difference
A LEFT JOIN means: join this table. If there is no connected record return with NULL. If there is one (or if there are more than one), return with all of them.
For your query, where you are joining the same table as the source table, that means:
Whenever there is no record found, where tblValues.NameFrom = X1.NameTo this field other will stay NULL... Why this happens nobody can tell you from outside...
It looks like you want to change LEFT JOIN to JOIN see a graphical explanation of SQL joins here: https://stackoverflow.com/a/406333/2054629.
Basically left join means
all rows from table A
matching rows of table B if found, else NULL
Your results from the X1 table are NULLs if there are no corresponding NameTo values for Table tblValues NameFrom. The Left Join includes all records from tblValues even if there are no corresponding matches in X1. Use an INNER JOIN:
Select 'From' = tblValues.NameFrom, 'To' = tblValues.NameTo, TblValues.Difference, 'Other' = x1.Difference
from tblValues
INNER JOIN tblValues X1 ON tblValues.NameFrom = X1.NameTo
AND tblValues.NameTo = X1.NameFrom
WHERE tblValues.NameFrom Like '%a%' OR tblValues.NameTo Like '%a%'
ORDER BY tblValues.NameFrom, tblValues.NameTo

SQL query to retrieve last record from a linked table [duplicate]

This question already has answers here:
SQL join: selecting the last records in a one-to-many relationship
(13 answers)
Closed 6 years ago.
I wrote a query to compare 2 columns in different tables (TRELAY VS TUSERDEF8). The query works great, except that it retrieves the top record in the TUSERDEF8 table which has a many to one relationship to the TRELAY table.
The tables are linked by TRELAY.ID = TUSERDEF8.N01. I would like to retrieve the latest record from TUSERDEF8 and compare that record with the TRELAY record. I plan to use the max value of the index column (TUSERDEF8.ID) to determine the latest record.
I am using SQL Server.
My code is below, but I'm not sure how to change the query to retrieve the last TUSERDEF8 record. Any help is appreciated.
SELECT
TRELAY.ID, TRELAY.S15,
TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM
TRELAY
INNER JOIN
TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE
LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
Making the assumption that your IDs are int(s) then the below might work?
SELECT TOP 1 TRELAY.ID, TRELAY.S15, TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM TRELAY INNER JOIN TUSERDEF8
ON TRELAY.ID = TUSERDEF8.N01
WHERE LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (
TRELAY.S15 LIKE '%MEDIUM%'
AND TUSERDEF8.S04 LIKE '%N/A%'
AND TUSERDEF8.S06 LIKE '%EACMS%'
)
ORDER BY TUSERDEF8.ID DESC
HTH
Dave
You could do this:
With cteLastRecord As
(
Select S04, N01, S06,
Row_Number() Over (Partition By N01, Order By ID Desc) SortOrder
From TUSERDEF8
)
SELECT
TRELAY.ID, TRELAY.S15,
TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM
TRELAY
INNER JOIN
(Select S04, N01, S06 From cteLastRecord Where SortOrder = 1) TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE
LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
I believe that your expected output is still a little ambiguous.
It sounds to me like you want only the record from the output where TUSERDEF8.ID is at its max. If that's correct, then try this:
SELECT TRELAY.ID, TRELAY.S15, TUSERDEF8.S04, TUSERDEF8.N01, TUSERDEF8.S06
FROM TRELAY
INNER JOIN TUSERDEF8 ON TRELAY.ID = TUSERDEF8.N01
WHERE LEFT(TRELAY.S15, 1) <> LEFT(TUSERDEF8.S04, 1)
AND NOT (TRELAY.S15 LIKE '%MEDIUM%' AND
TUSERDEF8.S04 LIKE '%N/A%' AND
TUSERDEF8.S06 LIKE '%EACMS%')
AND TUSERDEF8.ID IN (SELECT MAX(TUSERDEF8.ID) FROM TUSERDEF8)
EDIT: After reviewing your recent comments, it would seem something like this would be more suitable:
SELECT
, C.ID
, C.S15,
, D.S04
, D.N01
, D.S06
FROM (
SELECT A.ID, A.S15, MAX(B.ID) AS MaxID
FROM TRELAY AS A
INNER JOIN TUSERDEF8 AS B ON A.ID = B.N01
WHERE
LEFT(A.S15, 1) <> LEFT(B.S04, 1)
AND NOT (A.S15 LIKE '%MEDIUM%' AND
B.S04 LIKE '%N/A%' AND
B.S06 LIKE '%EACMS%')
GROUP BY A.ID, A.S15
) AS C
INNER JOIN TUSERDEF8 AS D ON C.ID = D.N01 AND C.MaxID = D.ID
Using an ID column to determine which row is "last" is a bad idea
Using cryptic table names like "TUSERDEF8" (how is it different from TUSERDEF7) is a very bad idea, along with completely cryptic column names like "S04".
Using prefixes like "T" for table is a bad idea - it should already be clear that it's a table.
Now that all of that is out of the way:
SELECT
R.ID,
R.S15,
U.S04,
U.N01,
U.S06
FROM
TRELAY R
INNER JOIN TUSERDEF8 U ON U.N01 = R.ID
LEFT OUTER JOIN TUSERDEF8 U2 ON
U2.N01 = R.ID AND
U2.ID > U.ID
WHERE
U2.ID IS NULL AND -- This will only happen if the LEFT OUTER JOIN above found no match, meaning that the row in U has the highest ID value of all matches
LEFT(R.S15, 1) <> LEFT(U.S04, 1) AND
NOT (
R.S15 LIKE '%MEDIUM%' AND
U.S04 LIKE '%N/A%' AND
U.S06 LIKE '%EACMS%'
)

SQL query: Iterate over values in table and use them in subquery

I have a simple SQL table containing some values, for example:
id | value (table 'values')
----------
0 | 4
1 | 7
2 | 9
I want to iterate over these values, and use them in a query like so:
SELECT value[0], x1
FROM (some subquery where value[0] is used)
UNION
SELECT value[1], x2
FROM (some subquery where value[1] is used)
...
etc
In order to get a result set like this:
4 | x1
7 | x2
9 | x3
It has to be in SQL as it will actually represent a database view. Of course the real query is a lot more complicated, but I tried to simplify the question while keeping the essence as much as possible.
I think I have to select from values and join the subquery, but as the value should be used in the subquery I'm lost on how to accomplish this.
Edit: I oversimplified my question; in reality I want to have 2 rows from the subquery and not only one.
Edit 2: As suggested I'm posting the real query. I simplified it a bit to make it clearer, but it's a working query and the problem is there. Note that I have hardcoded the value '2' in this query two times. I want to replace that with values from a different table, in the example table above I would want a result set of the combined results of this query with 4, 7 and 9 as values instead of the currently hardcoded 2.
SELECT x.fantasycoach_id, SUM(round_points)
FROM (
SELECT DISTINCT fc.id AS fantasycoach_id,
ffv.formation_id AS formation_id,
fpc.round_sequence AS round_sequence,
round_points,
fpc.fantasyplayer_id
FROM fantasyworld_FantasyCoach AS fc
LEFT JOIN fantasyworld_fantasyformation AS ff ON ff.id = (
SELECT MAX(fantasyworld_fantasyformationvalidity.formation_id)
FROM fantasyworld_fantasyformationvalidity
LEFT JOIN realworld_round AS _rr ON _rr.id = round_id
LEFT JOIN fantasyworld_fantasyformation AS _ff ON _ff.id = formation_id
WHERE is_valid = TRUE
AND _ff.coach_id = fc.id
AND _rr.sequence <= 2 /* HARDCODED USE OF VALUE */
)
LEFT JOIN fantasyworld_FantasyFormationPlayer AS ffp
ON ffp.formation_id = ff.id
LEFT JOIN dbcache_fantasyplayercache AS fpc
ON ffp.player_id = fpc.fantasyplayer_id
AND fpc.round_sequence = 2 /* HARDCODED USE OF VALUE */
LEFT JOIN fantasyworld_fantasyformationvalidity AS ffv
ON ffv.formation_id = ff.id
) x
GROUP BY fantasycoach_id
Edit 3: I'm using PostgreSQL.
SQL works with tables as a whole, which basically involves set operations. There is no explicit iteration, and generally no need for any. In particular, the most straightforward implementation of what you described would be this:
SELECT value, (some subquery where value is used) AS x
FROM values
Do note, however, that a correlated subquery such as that is very hard on query performance. Depending on the details of what you're trying to do, it may well be possible to structure it around a simple join, an uncorrelated subquery, or a similar, better-performing alternative.
Update:
In view of the update to the question indicating that the subquery is expected to yield multiple rows for each value in table values, contrary to the example results, it seems a better approach would be to just rewrite the subquery as the main query. If it does not already do so (and maybe even if it does) then it would join table values as another base table.
Update 2:
Given the real query now presented, this is how the values from table values could be incorporated into it:
SELECT x.fantasycoach_id, SUM(round_points) FROM
(
SELECT DISTINCT
fc.id AS fantasycoach_id,
ffv.formation_id AS formation_id,
fpc.round_sequence AS round_sequence,
round_points,
fpc.fantasyplayer_id
FROM fantasyworld_FantasyCoach AS fc
-- one row for each combination of coach and value:
CROSS JOIN values
LEFT JOIN fantasyworld_fantasyformation AS ff
ON ff.id = (
SELECT MAX(fantasyworld_fantasyformationvalidity.formation_id)
FROM fantasyworld_fantasyformationvalidity
LEFT JOIN realworld_round AS _rr
ON _rr.id = round_id
LEFT JOIN fantasyworld_fantasyformation AS _ff
ON _ff.id = formation_id
WHERE is_valid = TRUE
AND _ff.coach_id = fc.id
-- use the value obtained from values:
AND _rr.sequence <= values.value
)
LEFT JOIN fantasyworld_FantasyFormationPlayer AS ffp
ON ffp.formation_id = ff.id
LEFT JOIN dbcache_fantasyplayercache AS fpc
ON ffp.player_id = fpc.fantasyplayer_id
-- use the value obtained from values again:
AND fpc.round_sequence = values.value
LEFT JOIN fantasyworld_fantasyformationvalidity AS ffv
ON ffv.formation_id = ff.id
) x
GROUP BY fantasycoach_id
Note in particular the CROSS JOIN which forms the cross product of two tables; this is the same thing as an INNER JOIN without any join predicate, and it can be written that way if desired.
The overall query could be at least a bit simplified, but I do not do so because it is a working example rather than an actual production query, so it is unclear what other changes would translate to the actual application.
In the example I create two tables. See how outer table have an alias you use in the inner select?
SQL Fiddle Demo
SELECT T.[value], (SELECT [property] FROM Table2 P WHERE P.[value] = T.[value])
FROM Table1 T
This is a better way for performance
SELECT T.[value], P.[property]
FROM Table1 T
INNER JOIN Table2 p
on P.[value] = T.[value];
Table 2 can be a QUERY instead of a real table
Third Option
Using a cte to calculate your values and then join back to the main table. This way you have the subquery logic separated from your final query.
WITH cte AS (
SELECT
T.[value],
T.[value] * T.[value] as property
FROM Table1 T
)
SELECT T.[value], C.[property]
FROM Table1 T
INNER JOIN cte C
on T.[value] = C.[value];
It might be helpful to extract the computation to a function that is called in the SELECT clause and is executed for each row of the result set
Here's the documentation for CREATE FUNCTION for SQL Server. It's probably similar to whatever database system you're using, and if not you can easily Google for it.
Here's an example of creating a function and using it in a query:
CREATE FUNCTION DoComputation(#parameter1 int)
RETURNS int
AS
BEGIN
-- Do some calculations here and return the function result.
-- This example returns the value of #parameter1 squared.
-- You can add additional parameters to the function definition if needed
DECLARE #Result int
SET #Result = #parameter1 * #parameter1
RETURN #Result
END
Here is an example of using the example function above in a query.
SELECT v.value, DoComputation(v.value) as ComputedValue
FROM [Values] v
ORDER BY value

SQL Join / Union

I have two statements that I want to merge into one output.
Statement One:
select name from auxiliary_variable_inquiry
where inquiry_idbr_code = '063'
Returns the following list of names:
Name
------------
Affiliates
NetBookValue
Parents
Worldbase
Statement Two:
select name, value from auxiliary_variable_value
where inquiry_idbr_code = '063'
and ru_ref = 20120000008
and period = 200912
Returns the following:
Name Value
-------------------
Affiliates 112
NetBookValue 225.700
I would like to have an output like this:
Name Value
-------------------
Affiliates 112
NetBookValue 225.700
Parents 0
Worldbase 0
So basically, if the second query only returns 2 names and values, I'd still like to display the complete set of names from the first query, with no values. If all four values were returned by both queries, then all four would be displayed.
Sorry I must add, im using Ingres SQL so im unable to use the ISNULL function.
You can do a left join. This ensures that all records from the first table will stay included. Where value is null, no child record was found, and we use coalesce to display 0 in these cases.
select i.name, COALESCE(v.Value,0) from auxiliary_variable_inquiry i
left join auxiliary_variable_value v
on v.inquiry_idbr_code = i.inquiry_idbr_code
and v.ru_ref = 20120000008
and v.period = 200912
where i.inquiry_idbr_code = '063'
I'd recommend a self-JOIN using the LEFT OUTER JOIN syntax. Include your 'extra' conditions from the second query in the JOIN condition, while the first conditions stay in the WHERE, like this:
select a.name, CASE WHEN b.Value IS NULL THEN 0 ELSE b.Value END AS Value
from
auxiliary_variable_inquiry a
LEFT JOIN
auxiliary_variable_inquiry b ON
a.name = b.name and -- replace this with your real ID-based JOIN
a.inquiry_idbr_code = b.inquiry_idbr_code AND
b.ru_ref = 20120000008 AND
b.period = 200912
where a.inquiry_idbr_code = '063'
if i got right, you should use something like:
SELECT i.NAME,
v.NAME,
v.value
FROM auxiliary_variable_inquiry i
LEFT JOIN auxiliary_variable_value v
ON i.inquiry_idbr_code = v.inquiry_idbr_code
WHERE v.ru_ref = 20120000008
AND v.period = 200912