What I want to do is to get all records that have almost exact duplicates except that duplicates don't have an extra char at the beginning of 'name'
this is my sql query:
select * from tags as spaced inner join tags as not_spaced on not_spaced.name = substring(spaced.name, 2);
also I tried:
select * from tags as spaced where (select count(*) from tags as not_spaced where not_spaced.name = substring(spaced.name, 2)) > 0;
What I'm getting is... the SQL connection stops responding.
Thanks!
p.s. Sorry I haven't mentioned that the only field I need is name. All other fields are insignificant (if present).
Try something like this:
select all potentially duplicated fields except name , name
from tags union all
select all potentially duplicated fields except name , substring(name, 2) name
from tags
group by all potentially duplicated fields including name
having count(*) > 1
If the tables are very large, make an index on name and substring(name,2) to make it faster:
select t1.* from tags t1
inner join tags t2 on t1.name = substring(t2.name, 2)
Even with an Index, your query will require every record in spaced to be checked against every record in tags.
If each table has 1,000 records, that's 1,000,000 combinations.
You may be better off creating a temporary table with just two fields spaced.id, substring(t2.name, 2) as shortname, then index the shortname field. Joining on that temporary and indexed table will be much much faster.
Without knowing the DB, how the tables are indexed, etc, it's just trying different things until one gets better optimized...
Here is another query you can try:
SELECT name, count(*) c FROM (
SELECT name FROM tags
UNION ALL
SELECT substring(name, 2) AS name FROM tags
) AS t
GROUP BY name
Related
How can i use in table field values in the url
SQL Query wherein all 3 tables are joined
select * from nfojm_usedcar_variants cv
inner join nfojm_usedcar_products cp
inner join nfojm_usedcar_categories cc on
cc.id=cp.prod_cat_id and
cp.id=cv.v_prod_id and
cv.state='1' order by cv.id desc
Output as checked
Then it combines all 3 tables
nfojm_usedcar_variants
nfojm_usedcar_products
nfojm_usedcar_categories
However - all 3 tables have unique field i.e id (but with different values)
I need to pass on value of id and v_prod_id in a url
say url been :-
<a href="index.php?option=com_usedcar&pid='.$row->v_prod_id.'&vid='.$row->id.'">
But id been common field in most of the tables hence its not picking in correctly from nfojm_usedcar_variants,
Can some one help to modify a function so as to fetch in value of id and v_prod_id from the respective table of nfojm_usedcar_variants
thanks
If you have multiple tables in a join that share a common column name, and you need them, then alias them. Such as:
select a.id as aid,a.theName,b.id as bid,b.year
from tableA a
join tableB b
on b.id=a.id
then refer to those columns as aid and bid in your code that follows.
Try to avoid Ever doing a select *. Be explicit. You never know what comes flying out of a select * typically. And odds are you don't need it all. Select * is fine for messing around, but not for production code. And you can't control common column names with select *. We like to control things afterall, no?
I need to gather posts from two mysql tables that have different columns and provide a WHERE clause to each set of tables. I appreciate the help, thanks in advance.
This is what I have tried...
SELECT
blabbing.id,
blabbing.mem_id,
blabbing.the_blab,
blabbing.blab_date,
blabbing.blab_type,
blabbing.device,
blabbing.fromid,
team_blabbing.team_id
FROM
blabbing
LEFT OUTER JOIN
team_blabbing
ON team_blabbing.id = blabbing.id
WHERE
team_id IN ($team_array) ||
mem_id='$id' ||
fromid='$logOptions_id'
ORDER BY
blab_date DESC
LIMIT 20
I know that this is messy, but i'll admit, I am no mysql veteran. I'm a beginner at best... Any suggestions?
You could put the where-clauses in subqueries:
select
*
from
(select * from ... where ...) as alias1 -- this is a subquery
left outer join
(select * from ... where ...) as alias2 -- this is also a subquery
on
....
order by
....
Note that you can't use subqueries like this in a view definition.
You could also combine the where-clauses, as in your example. Use table aliases to distinguish between columns of different tables (it's a good idea to use aliases even when you don't have to, just because it makes things easier to read). Example:
select
*
from
<table> as alias1
left outer join
<othertable> as alias2
on
....
where
alias1.id = ... and alias2.id = ... -- aliases distinguish between ids!!
order by
....
Two suggestions for you since a relative newbie in SQL. Use "aliases" for your tables to help reduce SuperLongTableNameReferencesForColumns, and always qualify the column names in a query. It can help your life go easier, and anyone AFTER you to better know which columns come from what table, especially if same column name in different tables. Prevents ambiguity in the query. Your left join, I think, from the sample, may be ambigous, but confirm the join of B.ID to TB.ID? Typically a "Team_ID" would appear once in a teams table, and each blabbing entry could have the "Team_ID" that such posting was from, in addition to its OWN "ID" for the blabbing table's unique key indicator.
SELECT
B.id,
B.mem_id,
B.the_blab,
B.blab_date,
B.blab_type,
B.device,
B.fromid,
TB.team_id
FROM
blabbing B
LEFT JOIN team_blabbing TB
ON B.ID = TB.ID
WHERE
TB.Team_ID IN ( you can't do a direct $team_array here )
OR B.mem_id = SomeParameter
OR b.FromID = AnotherParameter
ORDER BY
B.blab_date DESC
LIMIT 20
Where you were trying the $team_array, you would have to build out the full list as expected, such as
TB.Team_ID IN ( 1, 4, 18, 23, 58 )
Also, not logical "||" or, but SQL "OR"
EDIT -- per your comment
This could be done in a variety of ways, such as dynamic SQL building and executing, calling multiple times, once for each ID and merging the results, or additionally, by doing a join to yet another temp table that gets cleaned out say... daily.
If you have another table such as "TeamJoins", and it has say... 3 columns: a date, a sessionid and team_id, you could daily purge anything from a day old of queries, and/or keep clearing each time a new query by the same session ID (as it appears coming from PHP). Have two indexes, one on the date (to simplify any daily purging), and second on (sessionID, team_id) for the join.
Then, loop through to do inserts into the "TempJoins" table with the simple elements identified.
THEN, instead of a hard-coded list IN, you could change that part to
...
FROM
blabbing B
LEFT JOIN team_blabbing TB
ON B.ID = TB.ID
LEFT JOIN TeamJoins TJ
on TB.Team_ID = TJ.Team_ID
WHERE
TB.Team_ID IN NOT NULL
OR B.mem_id ... rest of query
What I ended up doing is;
I added an extra column to my blabbing table called team_id and set it to null as well as another field in my team_blabbing table called mem_id
Then I changed the insert script to also insert a value to the mem_id in team_blabbing.
After doing this I did a simple UNION ALL in the query:
SELECT
*
FROM
blabbing
WHERE
mem_id='$id' OR
fromid='$logOptions_id'
UNION ALL
SELECT
*
FROM
team_blabbing
WHERE
team_id
IN
($team_array)
ORDER BY
blab_date DESC
LIMIT 20
I am open to any thought on what I did. Try not to be too harsh though:) Thanks again for all the info.
Basically, there is an attribute table and translation table - many translations for one attribute.
I need to select id and value from translation for each attribute in a specified language, even if there is no translation record in that language. Either I am missing some join technique or join (without involving language table) is not working here since the following do not return attributes with non-existing translations in the specified language.
select a.attribute, at.id, at.translation
from attribute a left join attributeTranslation at on a.id=at.attribute
where al.language=1;
So I am using subqueries like this, problem here is making two subqueries to the same table with the same parameters (feels like performance drain unless MySQL groups those, which I doubt since it makes you do many similar subqueries)
select attribute,
(select id from attributeTranslation where attribute=a.id and language=1),
(select translation from attributeTranslation where attribute=a.id and language=1),
from attribute a;
I would like to be able to get id and translation from one query, so I concat columns and get the id from string later, which is at least making single subquery but still not looking right.
select attribute,
(select concat(id,';',title)
from offerAttribute_language
where offerAttribute=a.id and _language=1
)
from offerAttribute a
So the question part.
Is there a way to get multiple columns from a single subquery or should I use two subqueries (MySQL is smart enough to group them?) or is joining the following way to go:
[[attribute to language] to translation] (joining 3 tables seems like a worse performance than subquery).
Yes, you can do this. The knack you need is the concept that there are two ways of getting tables out of the table server. One way is ..
FROM TABLE A
The other way is
FROM (SELECT col as name1, col2 as name2 FROM ...) B
Notice that the select clause and the parentheses around it are a table, a virtual table.
So, using your second code example (I am guessing at the columns you are hoping to retrieve here):
SELECT a.attr, b.id, b.trans, b.lang
FROM attribute a
JOIN (
SELECT at.id AS id, at.translation AS trans, at.language AS lang, a.attribute
FROM attributeTranslation at
) b ON (a.id = b.attribute AND b.lang = 1)
Notice that your real table attribute is the first table in this join, and that this virtual table I've called b is the second table.
This technique comes in especially handy when the virtual table is a summary table of some kind. e.g.
SELECT a.attr, b.id, b.trans, b.lang, c.langcount
FROM attribute a
JOIN (
SELECT at.id AS id, at.translation AS trans, at.language AS lang, at.attribute
FROM attributeTranslation at
) b ON (a.id = b.attribute AND b.lang = 1)
JOIN (
SELECT count(*) AS langcount, at.attribute
FROM attributeTranslation at
GROUP BY at.attribute
) c ON (a.id = c.attribute)
See how that goes? You've generated a virtual table c containing two columns, joined it to the other two, used one of the columns for the ON clause, and returned the other as a column in your result set.
I am joining two large tables in MySQL based on a unique identifier they both share. Because there are a large number of fields, I do not want to list out all fields after SELECT. Instead I want to select all fields, but I do not want recurring fields (the shared unique identifier in this case) to be repeated.
With this example query:
SELECT *
FROM Gr3_PracMath_Jan11_D1 as a, student_list_011811 as b
WHERE a.StudentID = b.StudentID
The field StudentID is repeated. Is there a way to prevent this?
I believe that if you do an explicit join with the USING keyword, you won't get a duplicate.
SELECT *
FROM Gr3_PracMath_Jan11_D1
LEFT JOIN student_list_011811
USING (StudentID)
I don't think there is. You might cut your work by listing only half the fields:
SELECT a.*, b.Field1, b.Field2...
It is bad practice to not list out all of the columns, even if there are a lot of them. Just bite the bullet and write them out.
I'm having trouble working out a query. I've tried subqueries, different joins and group_concat() but they either don't work or are painfully slow. This may be a bit complicated to explain, but here's the problem:
I have a table "item" (with about 2000 products). I have a table "tag" (which contains about 2000 different product tags). And I have a table "tagassign" (which connects the tags to the items, with about 200000 records).
I'm using the tag to define characteristics of the products, for example colour, compatibility, whether the product is on special offer etc. Now if I want to be able to show the products that have a certain tag assigned to them, I use a simple query like:
select * from item, tagassign
where item.itemid = tagassign.itemid
and tagassign.tagid = "specialoffer"
The problem is, that I may want to see items that have several tags. For example I might want to see only the black cell phone cases that are compatible with the Apple iPhone and are new. So I basically want to see all records from the item table, that have tags "black" and "case" and "iphone" and "new". The only way I can get this to work is to create 4 aliases (select * from item, tagassign, tagassign as t1, tagassign as t2, tagassign as t3 etc.). In some cases I might be looking for 10 or 20 different tags, and with that many records the queries are dreadfully slow.
I know I'm missing something obvious. Any ideas?
Thanks!
SELECT *
FROM item i
WHERE (
SELECT COUNT(*)
FROM tagassign ta
WHERE ta.tagid IN ('black', 'case', 'iphone', 'new')
AND ta.itemid = i.itemid
) = 4
Substitute the actual number of the tags you are searching for instead of 4.
Create a unique index or a primary key on tagassign (itemid, tagid) (in this order) for this to work fast.
If you are searching for lots of tags (or for tags that are used rarely), this query may also be faster:
SELECT i.*
FROM (
SELECT itemid
FROM tagassign ta
WHERE ta.tagid IN ('black', 'case', 'iphone', 'new')
GROUP BY
itemid
HAVING COUNT(*) = 4
) t
JOIN item i
ON i.itemid = t.itemid
For this query, you would need a unique index on tagassign (tagid, itemid).