MySql query for crosstable select - mysql

packages:
package_id, user_id
transactions:
product_id,user_id,package_id
I want to select rows in transactions that have package_id null or 0
but only when there are other transactions with same user_id where package id is greater than 0
is that possible. Sorry for bad English... I tried goggling it, but couldn't guess a correct question for Google query.
I know that title is not ok, so anybody please propose a better one.
Gwynnbleid1

Perhaps this...I try to avoid sub-selects at all costs, so it can get crazy and a bit confusing, and I never truly know if it works until I try.
SELECT DISTINCT T.*
FROM packages P
LEFT JOIN transactions T
ON P.user_id = T.user_id
LEFT JOIN transactions T2
ON T.user_id = T2.user_id
WHERE ( T.package_id IS NULL
OR T.package_id = 0 )
AND T2.package_id > 0

This query will give you all the transactions for package_id > 0 for users who have at least one other transaction with a NULL or 0 package_id.
SELECT * FROM transactions WHERE user_id IN
(SELECT user_id FROM transactions WHERE package_id IS NULL OR package_id = 0)
AND package_id > 0;

SELECT A.* FROM
(SELECT * FROM TRANSACTIONS WHERE (package_id = 0 or package_id is null)) A
(SELECT * FROM TRANSACTIONS WHERE package_id is not null) B
WHERE A.userID = B.userID

Related

MYSQL Count of duplicate records with condition

I'm trying to get count of duplicate data, but my query doesn't work correctly.
Every user should have one dev_id but when other user will have this same dev_id I want to know this
Table for example:
dev_id user_id
------------------
111 1
111 1
222 2
111 2
333 3
Should result:
user_id qu
------------------
1 1
2 1
3 0
This is my query
SELECT t1.user_id,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id
You can get results by doing:
select r.user_id, count(*) - 1
from reports r
group by r.user_id;
Is this the calculation that you want?
Okay. Let start from simple.
First you need get unique user_id/dev id combinations
select distinct dev_id,user_id from reports
Result will be
dev_id user_id
------------------
111 1
222 2
111 2
333 3
After that you should get number of different user_id per dev_id
select dev_id,c from (
SELECT
dev_id,
count(*)-1 AS c
FROM
(select distinct user_id,dev_id from reports) as fixed_reports
GROUP BY dev_id
) as counts
Result of such query will be
dev_id c
-----------------
111 1
222 0
333 0
Now you should show users which have such dev_id. For that you should join such dev_id list with table from step1(which show which one user_id,dev_id pairs exist)
select distinct fixed_reports2.user_id,counts.c from (
SELECT
dev_id,
count(*)-1 AS c
FROM
(select distinct user_id,dev_id from reports) as fixed_reports
GROUP BY dev_id
) as counts
join
(select distinct user_id,dev_id from reports) as fixed_reports2
on fixed_reports2.dev_id=counts.dev_id
where counts.c>0 and counts.c is not null
"Distinct" here need to skip same rows.
Result should be for internal query
dev_id c
-----------------
111 1
For all query
user_id c
------------------
1 1
2 1
If you sure you need also rows with c=0, then you need do "left join" of fixed_reports2 and large query,that way you will get all rows and rows with c=null will be rows with 0(can be changed by case/when statement)
I think following sql query should solve you problem:
SELECT t1.user_id, t1.dev_id, count(t2.user_id) as qu
FROM (Select Distinct * from reports) t1
Left Join (Select Distinct * from reports) t2
on t1.user_id != t2.user_id and t2.dev_id = t1.dev_id
group by t1.user_Id, t1.dev_id
SQL Fiddle Link
SELECT user_id, (COUNT(user_id) -1) as qu
FROM reports
GROUP BY user_id
This would give desired result in your case, however you can improve it a lot more.
Cheers,,
Your query is broken and would not run on many systems. The problem is that the group with user_id of 2 has two different dev_ids. If you run the "broken query" below you can see that the min() and max() are distinct but the subquery only sees one of those values which is randomly chosen. The last query is corrected by adding dev_id to the groupings which shows you where the "missing" row went in the counts.
SELECT -- broken query
t1.user_id, min(t1.dev_id), max(t1.dev_id),
(select distinct t1.dev_id from reports) as should_have_errored,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id;
-- On SQL Server that query returns an error
-- Msg 8120, Level 16, State 1, Line 7
-- Column 'reports.dev_id' is invalid in the select list because it is
-- not contained in either an aggregate function or the GROUP BY clause.
SELECT -- query that duplicates your original query
t1.user_id,
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = max(t1.dev_id) /* <-- see here */
) AS qu
FROM reports t1
GROUP BY t1.user_id;
SELECT t1.user_id, t1.dev_id, -- fixed query
(SELECT Count(DISTINCT t2.dev_id)
FROM reports t2
WHERE t2.user_id != t1.user_id
AND t2.dev_id = t1.dev_id
) AS qu
FROM reports t1
GROUP BY t1.user_id, t1.dev_id
http://sqlfiddle.com/#!9/6576e3/20
Here are some queries that might be useful:
Which dev_ids have multiple user_ids associated with them?
select dev_id
from reports
group by dev_id
having count(distinct user_id) > 1
Which other user_ids share a dev_id with this user_id?
select user_id
from reports r1
where exists (
select 1
from reports r2
where r2.dev_id = r1.dev_id and r2.user_id <> ?
)
Or really that's just equivalent to an inner join which also makes it easy to list everybody at once. Note that each pair will be listed twice:
select r1.user_id, r1.dev_id, r2.user_id as common_user_id
from
reports r1 inner join reports r2
on r2.dev_id = r1.dev_id
where
r1.user_id <> r2.user_id
order by
r1.user_id, r1.dev_id, r2.user_id
And since you've got duplicate rows in your table you'd need to make it select distinct to get unique rows.
Try
SELECT
user_id,
SUM(qu) AS qu
FROM (
SELECT
user_id,
count(*)-1 AS qu
FROM
reports
GROUP BY user_id, dev_id
) AS r
GROUP BY user_id
No need to do a join if all the data you need is in one table.
Edit: changed the group by to dev_id instead of user_id
Edit2: I think you need both dev_id and user_id in the group by clause.
Edit3: Added a subquery to get the desired result. This might be a little cumbersome, perhaps someone has a way to improve this?

use just one where for all UNION ALL selects

I have this select and I want to optimize it.
I was wondering if I could use for all this UNION ALL just one where instead of repeat this all the time making mysql scan table 4 times instead of just 1
select id from sells
where user_id in (select fv from favorite where user =?)
union all
select id from likes
where user_id in (select fv from favorite where user =?)
union all
select id from favorites
where user_id in (select fv from favorite where user =?)
union all
select id from comments
where user_id in (select fv from favorite where user =?)
is it possible? how can I change it?
select id,user_id from(
select id,user_id from sells
union all
select id,user_id from likes
union all
select id,user_id from favorites
union all
select id,user_id from comments
) as t
where user_id in (select fv from favorite where user =?)
You could do:
select user_id
from (select user_id from sells union all
select user_id from likes union all
select user_id from favorites union all
select user_id from comments
) x
where user_id in (select fv from favirote where user = ?);
However, I would discourage this because of performance. There are two hits. First, the subquery is materialized, which slows down processing. More importantly, the subqueries do not take advantage of indexes, further slowing down the query.
Your version is probably the most reasonable, assuming that you have proper indexes (on all the user_id columns and fv).
Also, if you don't want duplicates, use union instead of union all. I usually advocate union all, but this seems to be a case where duplicate removal is warranted.
Probably the most performant approach is this:
select f.fv
from favorites f
where f.user = ? and
(exists (select 1 from sells s where s.user_id = f.fv) or
exists (select 1 from likes l where l.user_id = f.fv) or
exists (select 1 from favorites f where s.user_id = f.fv) or
exists (select 1 from comments c where s.user_id = c.fv)
);
This can make use of indexes and doesn't require additional overhead.

MySQL slow on subquery

This following query take 1-2 seconds for querying.
SELECT updated, COUNT( * ) count
FROM v2_subscription
WHERE ss_id IN (SELECT MAX(ss_id) ss_id FROM v2_subscription GROUP BY uid, card_id)
while the subquery do take only few milliseconds.
SELECT MAX(ss_id) ss_id FROM v2_subscription GROUP BY uid, card_id
I do have index on uid, card_id and both uid, card_id
It's my sql and i have no idea how to optimize this.
Please advise,
Try this, May be it would help, let me know, if it does.
SELECT a.updated, COUNT( * ) count
FROM v2_subscription a
inner join v2_subscription b
on a.ss_id = max(b.ss_id)
GROUP BY b.uid, b.card_id
Or perhaps this
SELECT a.updated, COUNT( * ) count
FROM v2_subscription a
inner join v2_subscription b
on a.ss_id = (SELECT MAX(b.ss_id) b.ss_id FROM v2_subscription b GROUP BY b.uid, b.card_id)
Finally i have found the solution beside #arkumar above answer.
Adding "ORDER BY ss_id" inside the subquery also do the trick
Since without order by, the result of subquery do not have index.

Count subselect elements according to parent id

I'm having this MySQL Query
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
(
SELECT
COUNT(*)
FROM liketbl t2
WHERE
t1.article_id=t2.article_id
) as totallike
FROM liketbl t1
WHERE
user_id = 1;
I need to get article id, user id and liked date in one run with the number of total entries.
Subselect is, in my opinion the easiest was to achieve this.
(Don't want to run several queries in client entviroment.
But is not working.
Don't know why, help is appreceated.
try this :
SELECT t1.article_id,
t1.user_id,
t1.like_date,
COUNT(*) as totallike
FROM liketbl t1 inner join liketbl t2 on t1.article_id=t2.article_id
WHERE user_id = 1
group by t1.article_id,t1.user_id,t1.like_date;
My guess is that you need to filter on user_id = 1 in the subquery to get what you expect.
The where only operates on the outer select.
This should work
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
count(SELECT * FROM liketbl t2 WHERE
t1.article_id=t2.article_id ) as totallike
FROM liketbl t1
WHERE
user_id = 1;
Scalar Subqueries tend to be the worst case, it's usually more efficient to rewrite them.
Depending on the number of rows in both tables this is another approach using a Derived Table:
SELECT
t1.article_id
,t1.user_id
.t1.like_date
,t2.totallike
FROM liketbl t1
JOIN
(
SELECT
article_id
,COUNT(*) AS totallike
FROM liketbl
GROUP BY article_id
) AS t2
ON t1.article_id=t2.article_id
WHERE
user_id = 1;

Struggling with a SQL Query

I've got a table called transaction
Transaction:
User_Id: int
Transaction_Type: int
Amount: int
How would I query all users that do not have transaction type 1.
SELECT * FROM Transaction WHERE Transaction_Type <> 1 Group By User_Id
seems to return all users & their transaction types that are not = to 1. I need all users that are missing / have no record of type 1.
This can be done with an IN() subquery
SELECT DISTINCT User_Id FROM Transaction
WHERE User_Id NOT IN (SELECT DISTINCT User_Id FROM Transaction WHERE Transaction_Type = 1)
Or with a NOT EXISTS
SELECT
DISTINCT User_Id
FROM Transaction t
WHERE
NOT EXISTS (SELECT User_Id FROM Transaction tn WHERE Transaction_Type = 1)
AND t.User_Id = tn.User_Id
There's probably a more elegant way of doing this, but this should work:
SELECT * FROM Transaction WHERE User_Id NOT IN (SELECT User_Id FROM Transaction WHERE Transaction_Type = 1)
SELECT *
FROM ( SELECT DISTINCT User_Id FROM Transaction ) AS User
LEFT JOIN Transaction ON Transaction.User_Id = User.id
AND Transaction.Transaction_Id != 1
WHERE Transaction.Transaction_Id IS NULL
GROUP BY User.id
SELECT DISTINCT User_Id
FROM Transaction
WHERE Transaction_Id <> 1
GROUP BY User_Id
This gets each User_Id which has at least one transaction which is not of type 1. If you also want the ones with no transactions, add OR Transaction_Id IS NULL to the WHERE statement.
For example
SELECT DISTINCT User_Id
FROM [Transaction]
EXCEPT
SELECT User_Id
FROM [Transaction]
WHERE Transaction_Id = 1
That's if you don't have a separate table for users. If you do, then use an outer join.
I would suggest not using keywords (like Transaction) as table/column names
I'd do this with a JOIN. Assuming a Users table:
SELECT u.*
FROM Users u
LEFT JOIN Transaction t
ON t.User_ID = u.User_ID
AND t.Transaction_Type = 1
WHERE t.User_ID IS NULL
This method avoids the subquery and DISTINCT.